在ASP.NET 2.0中操作數(shù)據(jù)之三十七:DataList批量更新
導(dǎo)言
在前面我們學(xué)習(xí)了如何創(chuàng)建item級(jí)的DataList。和可編輯的GridView一樣,每個(gè)DataList里的item都包含一個(gè)Edit button,當(dāng)點(diǎn)擊時(shí),item會(huì)變的可編輯。item級(jí)的編輯在偶爾需要更新時(shí)沒什么問題,但是在有些情況下用戶需要編輯大量的記錄。如果一個(gè)用戶需要編輯許多記錄,他會(huì)被迫去不停的去點(diǎn)擊Edit,作出修改,然后點(diǎn)擊Update,這些大量的點(diǎn)擊會(huì)妨礙他的工作效率。在這樣的情況下,一個(gè)好的選擇是提供一個(gè)完全可編輯的DataList,它的所有的item都處于編輯模式下,它的所有的值都可以通過點(diǎn)擊一個(gè)“Update All”button來更新。見圖1。
圖 1: 一個(gè)完全可編輯的DataList 的所有item都可以被修改
本章我們來學(xué)習(xí)如何創(chuàng)建一個(gè)完全可編輯的DataList,它提供用戶更新supplier的address的功能。
第一步: 在DataList的 ItemTemplate創(chuàng)建一個(gè)可編輯的用戶界面
在前面創(chuàng)建一個(gè)標(biāo)準(zhǔn)的item級(jí)編輯的DataList時(shí),我們使用了兩個(gè)template:
ItemTemplate — 包含只讀的用戶界面(使用 Label 顯示每個(gè)product的 name 和price).
EditItemTemplate — 包含編輯的用戶界面(兩個(gè)TextBox ).
DataList的EditItemIndex屬性表明了哪個(gè)DataListItem使用EditItemTemplate來展示(如果有的話)。即ItemIndex的值等于DataList的EditItemIndex的DataListItem使用EditItemTemplate來展示。在一次只編輯一個(gè)item的情況下,這個(gè)模式工作的很好,但是在創(chuàng)建完全可編輯的DataList的時(shí)候就不適用了。
對(duì)完全可編輯的DataList來說,我們需要所有的DataListItem都以可編輯的界面來展示。最簡(jiǎn)單的方法是在ItemTemplate里定義可編輯的界面。對(duì)修改supplier的address信息而言,可編輯界面里supplier表現(xiàn)為文本,address,city和country的值都用TextBox來表示。
首先打開BatchUpdate.aspx頁,添加一個(gè)DataList,將ID設(shè)為Suppliers。通過智能標(biāo)簽添加一個(gè)名為SuppliersDataSource的ObjectDataSource控件。
圖2: 創(chuàng)建一個(gè)名為SuppliersDataSource的ObjectDataSource
使用SuppliersBLL類的GetSuppliers()方法配置ObjectDataSource(見圖3)。象前面一章那樣,我們將直接使用 BLL而不是通過ObjectDataSource來更新supplier信息。在UPDATE標(biāo)簽里選擇None(見圖4)。
圖 3: 使用GetSuppliers() 方法配置ObjectDataSource
圖 4: 設(shè)置UPDATE 標(biāo)簽為None
完成向?qū)Ш?,Visual Studio會(huì)自動(dòng)生成DataList的ItemTemplate來在Label里顯示每個(gè)數(shù)據(jù)字段。我們需要修改這個(gè)template讓它提供編輯界面。ItemTemplate可以在設(shè)計(jì)器里通過DataList的智能標(biāo)簽上的Edit Templates或直接寫聲明語法來自定義。
創(chuàng)建一個(gè)編輯界面,將supplier的name表現(xiàn)為文本,address,city和country表現(xiàn)為TextBox。完成這些后,你的聲明代碼應(yīng)該和下面差不多:
<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID" DataSourceID="SuppliersDataSource"> <ItemTemplate> <h4><asp:Label ID="CompanyNameLabel" runat="server" Text='<%# Eval("CompanyName") %>' /></h4> <table border="0"> <tr> <td class="SupplierPropertyLabel">Address:</td> <td class="SupplierPropertyValue"> <asp:TextBox ID="Address" runat="server" Text='<%# Eval("Address") %>' /> </td> </tr> <tr> <td class="SupplierPropertyLabel">City:</td> <td class="SupplierPropertyValue"> <asp:TextBox ID="City" runat="server" Text='<%# Eval("City") %>' /> </td> </tr> <tr> <td class="SupplierPropertyLabel">Country:</td> <td class="SupplierPropertyValue"> <asp:TextBox ID="Country" runat="server" Text='<%# Eval("Country") %>' /> </td> </tr> </table> <br /> </ItemTemplate> </asp:DataList> <asp:ObjectDataSource ID="SuppliersDataSource" runat="server" OldValuesParameterFormatString="original_{0}" SelectMethod="GetSuppliers" TypeName="SuppliersBLL"> </asp:ObjectDataSource>
注意:和前面一章一樣,需要為DataList開啟view state。
在ItemTemplate里我使用了兩個(gè)新的CSS類,SupplierPropertyLabel和SupplierPropertyValue。它們的風(fēng)格設(shè)置和ProductsPropertyLabel和ProductPropertyValue CSS類一樣,并已經(jīng)加入到Styles.css中。
.ProductPropertyLabel, .SupplierPropertyLabel { font-weight: bold; text-align: right; } .ProductPropertyValue, .SupplierPropertyValue { padding-right: 35px; }
完成這些后瀏覽頁面。如圖5所示,每個(gè)DataList的item用文本顯示supplier name,用TextBox顯示address,city和country。
圖 5: DataList里的每個(gè)Supplier都可編輯
第二步: 增加“Update All” Button
圖5里顯示的信息暫時(shí)還沒提供Update按鈕。完全可編輯的DataList應(yīng)該只包含一個(gè)"Update All"按鈕,而不是象前面那樣,每個(gè)item包含一個(gè)button。當(dāng)點(diǎn)擊"Update All"時(shí),DataList里的所有記錄將被更新。本章我們將添加兩個(gè)"Update All"button- 一個(gè)在頁的上面,一個(gè)在下面(兩個(gè)都提供相同的功能)。
先在DataList上面添加一個(gè)ID為UpdateAll1的Button。然后在DataList下面添加ID為UpdataAll2的Button。兩個(gè)Button的Text都設(shè)為"Update All"。最后為兩個(gè)Button的Click事件都創(chuàng)建一個(gè)event handler。我們創(chuàng)建一個(gè)方法,“UpdateAllSupplierAddress”,然后在事件處理中調(diào)用它。(而不是在兩個(gè)事件處理里復(fù)制相同的代碼)
protected void UpdateAll1_Click(object sender, EventArgs e) { UpdateAllSupplierAddresses(); } protected void UpdateAll2_Click(object sender, EventArgs e) { UpdateAllSupplierAddresses(); } private void UpdateAllSupplierAddresses() { // TODO: Write code to update _all_ of the supplier addresses in the DataList }
圖6是添加完"Update All"button后的頁面。
圖 6: 頁面添加了兩個(gè)“Update All” Button
第三步: 更新所有的Suppliers的 Address 信息
完成了將所有的item顯示為可編輯的界面和添加了“Update All”button后,剩下的事就是寫代碼執(zhí)行批量更新。我們需要便利DataList的item,調(diào)用SuppliersBLL類的UpdateSupplierAddress方法。
可以通過DataList的Items property 來訪問DataListItem集合。通過DataListItem的引用,我們可以從DataKeys集合里獲取相關(guān)的SuppliserID,并引用ItemTemplate里的TextBox,見下面的代碼:
private void UpdateAllSupplierAddresses() { // Create an instance of the SuppliersBLL class SuppliersBLL suppliersAPI = new SuppliersBLL(); // Iterate through the DataList's items foreach (DataListItem item in Suppliers.Items) { // Get the supplierID from the DataKeys collection int supplierID = Convert.ToInt32(Suppliers.DataKeys[item.ItemIndex]); // Read in the user-entered values TextBox address = (TextBox)item.FindControl("Address"); TextBox city = (TextBox)item.FindControl("City"); TextBox country = (TextBox)item.FindControl("Country"); string addressValue = null, cityValue = null, countryValue = null; if (address.Text.Trim().Length > 0) addressValue = address.Text.Trim(); if (city.Text.Trim().Length > 0) cityValue = city.Text.Trim(); if (country.Text.Trim().Length > 0) countryValue = country.Text.Trim(); // Call the SuppliersBLL class's UpdateSupplierAddress method suppliersAPI.UpdateSupplierAddress (supplierID, addressValue, cityValue, countryValue); } }
當(dāng)用戶點(diǎn)擊一個(gè)"Update All"button時(shí),每個(gè)Supplier DataList里的DataListItem都執(zhí)行UpdateAllSupplierAddress方法,并調(diào)用SuppliersBLL類的UpdateSupplierAddress方法,將相關(guān)的值傳過去。如果address,city或country里不輸入值,UpdateSupplierAddress會(huì)接收一個(gè)空值(不是空字符串),而相關(guān)的字段的結(jié)果會(huì)是一個(gè)database NULL。
注意:你可以添加一個(gè)顯示的狀態(tài)Label,當(dāng)批量更新完成后通過它來提供一些確認(rèn)信息。只更新 Addresses被修改過的記錄
本章使用的批量更新法則為每個(gè)DataList里的supplier調(diào)用UpdateSupplierAddress方法,無論address信息是否被修改過。雖然這種盲目的更新一般情況下不會(huì)有什么性能問題,但是如果你有做數(shù)據(jù)庫表的審計(jì),那樣將會(huì)導(dǎo)致很多多余的記錄。每次用戶點(diǎn)擊"Update All"button后,不管用戶是否有修改,系統(tǒng)里都會(huì)為每個(gè)supplier產(chǎn)生一個(gè)一條新的審計(jì)記錄。
ADO.NET的DateTable和DataAdapter類被設(shè)計(jì)用來支持批量更新那些僅僅被修改,刪除或新增的記錄。DataTable的每個(gè)row都有RowState property 來指明這個(gè)row是否是新增到DataTable或從它里面刪除,修改,或沒有改變。當(dāng)DataTable剛產(chǎn)生時(shí),所有的row都被標(biāo)記為未修改的,修改了row的任何列后row會(huì)被標(biāo)記為已修改的。
在SuppliersBLL類里我們首先將supplier的記錄讀進(jìn)SuppliersDataTable里然后設(shè)置Address,City和Country列的值來更新指定的supplier的信息,見以下代碼:
public bool UpdateSupplierAddress (int supplierID, string address, string city, string country) { Northwind.SuppliersDataTable suppliers = Adapter.GetSupplierBySupplierID(supplierID); if (suppliers.Count == 0) // no matching record found, return false return false; else { Northwind.SuppliersRow supplier = suppliers[0]; if (address == null) supplier.SetAddressNull(); else supplier.Address = address; if (city == null) supplier.SetCityNull(); else supplier.City = city; if (country == null) supplier.SetCountryNull(); else supplier.Country = country; // Update the supplier Address-related information int rowsAffected = Adapter.Update(supplier); // Return true if precisely one row was updated, // otherwise false return rowsAffected == 1; } }
無論值是否有被修改,這段代碼都將傳入的address,city和country的值賦給SuppliersDataTable的SuppliersRow。這個(gè)修改將使SuppliersRow的RowState屬性被標(biāo)記為已修改的。當(dāng)DAL的Update方法被調(diào)用時(shí),它發(fā)現(xiàn)SupplierRow已經(jīng)被修改了,因此向數(shù)據(jù)庫發(fā)送UPDATE命令。
然而想象一下,我們?yōu)檫@個(gè)方法添加的代碼僅僅在和已經(jīng)存在的值不一樣時(shí)才將傳入的address,city和country的值賦給SuppliersRow。在address,city和country沒有修改的情況下,SupplierRow的RowState仍然標(biāo)記為未改變。這樣的結(jié)果是當(dāng)DAL的Update方法被調(diào)用時(shí),SuppliersRow沒有被修改,因此不會(huì)調(diào)用數(shù)據(jù)庫。使用以下的代碼代替前面盲目的賦值:
// Only assign the values to the SupplierRow's column values if they differ if (address == null && !supplier.IsAddressNull()) supplier.SetAddressNull(); else if ((address != null && supplier.IsAddressNull()) || (!supplier.IsAddressNull() && string.Compare(supplier.Address, address) != 0)) supplier.Address = address; if (city == null && !supplier.IsCityNull()) supplier.SetCityNull(); else if ((city != null && supplier.IsCityNull()) || (!supplier.IsCityNull() && string.Compare(supplier.City, city) != 0)) supplier.City = city; if (country == null && !supplier.IsCountryNull()) supplier.SetCountryNull(); else if ((country != null && supplier.IsCountryNull()) || (!supplier.IsCountryNull() && string.Compare(supplier.Country, country) != 0)) supplier.Country = country;
增加了這些代碼后,DAL的Update方法僅僅在更改過address相關(guān)的值的那些記錄里才向數(shù)據(jù)庫發(fā)送UPDATE命令。
當(dāng)然我們也可以追蹤傳入的字段和數(shù)據(jù)庫數(shù)據(jù)是否有區(qū)別,如果沒有,就不需要調(diào)用DAL的Update方法。這種方法在你使用直接的數(shù)據(jù)庫命令時(shí)非常有效,因?yàn)橹苯拥臄?shù)據(jù)庫命令不會(huì)檢查SuppliersRow來決定是否需要調(diào)用數(shù)據(jù)庫。
注意:每次UpdateSupplierAddress方法被調(diào)用時(shí),都會(huì)調(diào)用一次數(shù)據(jù)庫來獲取需要更新的記錄的信息。如果數(shù)據(jù)被修改,又要調(diào)用一次數(shù)據(jù)庫來更新數(shù)據(jù)。這個(gè)流程可以通過創(chuàng)建一個(gè)重載的UpdateSupplierAddress方法來優(yōu)化,這個(gè)方法接受一個(gè)EmployeesDataTable ,它包含BatchUpdate.aspx頁的所有的修改。然后它會(huì)調(diào)用一次數(shù)據(jù)庫來獲取Suppliers表里的所有記錄。在結(jié)果集里僅僅是被修改過的記錄才能被更新。
總結(jié)
本章學(xué)習(xí)了如何創(chuàng)建一個(gè)完全可編輯的DataList。通過它用戶可以快速的修改多個(gè)supplier的address信息。我們首先定義了編輯界面 — address,city和country都以TextBox來表示 — 在DataList的ItemTemplate里。然后我們?cè)贒ataList的上下各添加了一個(gè)“Update All”button。用戶修改完后,點(diǎn)擊其中一個(gè)后,每個(gè)DataListItem都會(huì)調(diào)用SuppliersBLL類的UpdateSupplierAddress方法。
祝編程愉快!
作者簡(jiǎn)介
本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創(chuàng)始人,自1998年以來一直應(yīng)用 微軟Web技術(shù)。大家可以點(diǎn)擊查看全部教程《[翻譯]Scott Mitchell 的ASP.NET 2.0數(shù)據(jù)教程》,希望對(duì)大家的學(xué)習(xí)ASP.NET有所幫助。
- C#.NET中如何批量插入大量數(shù)據(jù)到數(shù)據(jù)庫中
- Asp.Net使用Bulk實(shí)現(xiàn)批量插入數(shù)據(jù)
- C#/.Net 中快速批量給SQLite數(shù)據(jù)庫插入測(cè)試數(shù)據(jù)
- asp.net新聞列表生成靜態(tài)頁之批量和單頁生成
- 在ASP.NET 2.0中操作數(shù)據(jù)之六十二:GridView批量更新數(shù)據(jù)
- 在ASP.NET 2.0中操作數(shù)據(jù)之六十四:GridView批量添加數(shù)據(jù)
- ajax readyState的五種狀態(tài)詳解
- AJAX(XMLHttpRequest.status)狀態(tài)碼
- javascript學(xué)習(xí)筆記(七)Ajax和Http狀態(tài)碼
- asp.net線程批量導(dǎo)入數(shù)據(jù)時(shí)通過ajax獲取執(zhí)行狀態(tài)
相關(guān)文章
《解剖PetShop》之一:PetShop的系統(tǒng)架構(gòu)設(shè)計(jì)
PetShop是一個(gè)范例,微軟用它來展示.Net企業(yè)系統(tǒng)開發(fā)的能力。本文主要講解PetShop4.0的系統(tǒng)架構(gòu)設(shè)計(jì),需要的朋友可以參考下。2016-05-05ASP.NET MVC4入門教程(九):查詢?cè)敿?xì)信息和刪除記錄
本文主要是MVC實(shí)戰(zhàn),介紹如何查詢和刪除信息,進(jìn)行到這一步,您已經(jīng)有一個(gè)完整的MVC案例了,創(chuàng)建、 讀取、 更新、 刪除和搜索等功能也都做了演示。2016-04-04解讀ASP.NET 5 & MVC6系列教程(12):基于Lamda表達(dá)式的強(qiáng)類型Routing實(shí)現(xiàn)
這篇文章主要介紹了基于ASP.NET 5 Lamda表達(dá)式的強(qiáng)類型Routing實(shí)現(xiàn),需要的朋友可以參考下2016-06-06NopCommerce架構(gòu)分析(一)Autofac依賴注入類生成容器
本文介紹了NopCommerce中IOC框架Autofac的使用,Autofac是一款I(lǐng)OC框架,比較于其他的IOC框架,如Spring.NET,Unity,Castle等等所包含的,它很輕量級(jí)性能上非常高。2016-04-04Microsoft .Net Remoting系列教程之一:.Net Remoting基礎(chǔ)篇
本文主要講解.Net Remoting的基礎(chǔ),需要的朋友可以參考下。2016-05-05在ASP.NET 2.0中操作數(shù)據(jù)之十一:基于數(shù)據(jù)的自定義格式化
GridView, DetailsView, FormView的格式自定義可以有多種方法, 在本文中我們將用DataBound 和 RowDataBound兩種事件來完成,下面主要演示了貨幣、加粗、斜體、高亮的數(shù)據(jù)格式化。2016-05-05Microsoft .Net Remoting系列教程之二:Marshal、Disconnect與生命周期以及跟蹤服務(wù)
本文主要講解.Net Remoting中Marshal、Disconnect與生命周期以及跟蹤服務(wù),需要的朋友可以參考下。2016-05-05