37批量更新.docx
《37批量更新.docx》由会员分享,可在线阅读,更多相关《37批量更新.docx(10页珍藏版)》请在冰豆网上搜索。
![37批量更新.docx](https://file1.bdocx.com/fileroot1/2022-11/25/870c742f-7b02-4bf5-befc-92212aaa6b6b/870c742f-7b02-4bf5-befc-92212aaa6b6b1.gif)
37批量更新
导言
在前面我们学习了如何创建item级的DataList。
和可编辑的GridView一样,每个DataList里的item都包含一个Editbutton,当点击时,item会变的可编辑。
item级的编辑在偶尔需要更新时没什么问题,但是在有些情况下用户需要编辑大量的记录。
如果一个用户需要编辑许多记录,他会被迫去不停的去点击Edit,作出修改,然后点击Update,这些大量的点击会妨碍他的工作效率。
在这样的情况下,一个好的选择是提供一个完全可编辑的DataList,它的所有的item都处于编辑模式下,它的所有的值都可以通过点击一个“UpdateAll”button来更新。
见图1。
图1:
一个完全可编辑的DataList的所有item都可以被修改
本章我们来学习如何创建一个完全可编辑的DataList,它提供用户更新supplier的address的功能。
第一步:
在DataList的ItemTemplate创建一个可编辑的用户界面
在前面创建一个标准的item级编辑的DataList时,我们使用了两个template:
ItemTemplate—包含只读的用户界面(使用Label显示每个product的name和price).
EditItemTemplate—包含编辑的用户界面(两个TextBox).
DataList的EditItemIndex属性表明了哪个DataListItem使用EditItemTemplate来展示(如果有的话)。
即ItemIndex的值等于DataList的EditItemIndex的DataListItem使用EditItemTemplate来展示。
在一次只编辑一个item的情况下,这个模式工作的很好,但是在创建完全可编辑的DataList的时候就不适用了。
对完全可编辑的DataList来说,我们需要所有的DataListItem都以可编辑的界面来展示。
最简单的方法是在ItemTemplate里定义可编辑的界面。
对修改supplier的address信息而言,可编辑界面里supplier表现为文本,address,city和country的值都用TextBox来表示。
首先打开BatchUpdate.aspx页,添加一个DataList,将ID设为Suppliers。
通过智能标签添加一个名为SuppliersDataSource的ObjectDataSource控件。
图2:
创建一个名为SuppliersDataSource的ObjectDataSource
使用SuppliersBLL类的GetSuppliers()方法配置ObjectDataSource(见图3)。
象前面一章那样,我们将直接使用BLL而不是通过ObjectDataSource来更新supplier信息。
在UPDATE标签里选择None(见图4)。
图3:
使用GetSuppliers()方法配置ObjectDataSource
图4:
设置UPDATE标签为None
完成向导后,VisualStudio会自动生成DataList的ItemTemplate来在Label里显示每个数据字段。
我们需要修改这个template让它提供编辑界面。
ItemTemplate可以在设计器里通过DataList的智能标签上的EditTemplates或直接写声明语法来自定义。
创建一个编辑界面,将supplier的name表现为文本,address,city和country表现为TextBox。
完成这些后,你的声明代码应该和下面差不多:
ASP.NET
DataListID="Suppliers"runat="server"DataKeyField="SupplierID"
DataSourceID="SuppliersDataSource">
LabelID="CompanyNameLabel"runat="server"Text='<%#Eval("CompanyName")%>'>
Label>
Address:
TextBoxID="Address"runat="server"Text='<%#Eval("Address")%>'/>
|
City:
TextBoxID="City"runat="server"Text='<%#Eval("City")%>'/>
|
Country:
TextBoxID="Country"runat="server"Text='<%#Eval("Country")%>'/>
|
DataList>
ObjectDataSourceID="SuppliersDataSource"runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetSuppliers"TypeName="SuppliersBLL">
ObjectDataSource>
注意:
和前面一章一样,需要为DataList开启viewstate。
在ItemTemplate里我使用了两个新的CSS类,SupplierPropertyLabel和SupplierPropertyValue。
它们的风格设置和ProductsPropertyLabel和ProductPropertyValueCSS类一样,并已经加入到Styles.css中。
CSS
.ProductPropertyLabel,.SupplierPropertyLabel
{
font-weight:
bold;
text-align:
right;
}
.ProductPropertyValue,.SupplierPropertyValue
{
padding-right:
35px;
}
完成这些后浏览页面。
如图5所示,每个DataList的item用文本显示suppliername,用TextBox显示address,city和country。
图5:
DataList里的每个Supplier都可编辑
第二步:
增加“UpdateAll”Button
图5里显示的信息暂时还没提供Update按钮。
完全可编辑的DataList应该只包含一个"UpdateAll"按钮,而不是象前面那样,每个item包含一个button。
当点击"UpdateAll"时,DataList里的所有记录将被更新。
本章我们将添加两个"UpdateAll"button-一个在页的上面,一个在下面(两个都提供相同的功能)。
先在DataList上面添加一个ID为UpdateAll1的Button。
然后在DataList下面添加ID为UpdataAll2的Button。
两个Button的Text都设为"UpdateAll"。
最后为两个Button的Click事件都创建一个eventhandler。
我们创建一个方法,“UpdateAllSupplierAddress”,然后在事件处理中调用它。
(而不是在两个事件处理里复制相同的代码)
C#
protectedvoidUpdateAll1_Click(objectsender,EventArgse)
{
UpdateAllSupplierAddresses();
}
protectedvoidUpdateAll2_Click(objectsender,EventArgse)
{
UpdateAllSupplierAddresses();
}
privatevoidUpdateAllSupplierAddresses()
{
//TODO:
Writecodetoupdate_all_ofthesupplieraddressesintheDataList
}
图6是添加完"UpdateAll"button后的页面。
图6:
页面添加了两个“UpdateAll”Button
第三步:
更新所有的Suppliers的Address信息
完成了将所有的item显示为可编辑的界面和添加了“UpdateAll”button后,剩下的事就是写代码执行批量更新。
我们需要便利DataList的item,调用SuppliersBLL类的UpdateSupplierAddress方法。
可以通过DataList的Itemsproperty来访问DataListItem集合。
通过DataListItem的引用,我们可以从DataKeys集合里获取相关的SuppliserID,并引用ItemTemplate里的TextBox,见下面的代码:
C#
privatevoidUpdateAllSupplierAddresses()
{
//CreateaninstanceoftheSuppliersBLLclass
SuppliersBLLsuppliersAPI=newSuppliersBLL();
//IteratethroughtheDataList'sitems
foreach(DataListItemiteminSuppliers.Items)
{
//GetthesupplierIDfromtheDataKeyscollection
intsupplierID=Convert.ToInt32(Suppliers.DataKeys[item.ItemIndex]);
//Readintheuser-enteredvalues
TextBoxaddress=(TextBox)item.FindControl("Address");
TextBoxcity=(TextBox)item.FindControl("City");
TextBoxcountry=(TextBox)item.FindControl("Country");
stringaddressValue=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();
//CalltheSuppliersBLLclass'sUpdateSupplierAddressmethod
suppliersAPI.UpdateSupplierAddress
(supplierID,addressValue,cityValue,countryValue);
}
}
当用户点击一个"UpdateAll"button时,每个SupplierDataList里的DataListItem都执行UpdateAllSupplierAddress方法,并调用SuppliersBLL类的UpdateSupplierAddress方法,将相关的值传过去。
如果address,city或country里不输入值,UpdateSupplierAddress会接收一个空值(不是空字符串),而相关的字段的结果会是一个databaseNULL。
注意:
你可以添加一个显示的状态Label,当批量更新完成后通过它来提供一些确认信息。
只更新Addresses被修改过的记录
本章使用的批量更新法则为每个DataList里的supplier调用UpdateSupplierAddress方法,无论address信息是否被修改过。
虽然这种盲目的更新一般情况下不会有什么性能问题,但是如果你有做数据库表的审计,那样将会导致很多多余的记录。
每次用户点击"UpdateAll"button后,不管用户是否有修改,系统里都会为每个supplier产生一个一条新的审计记录。
ADO.NET的DateTable和DataAdapter类被设计用来支持批量更新那些仅仅被修改,删除或新增的记录。
DataTable的每个row都有RowStateproperty来指明这个row是否是新增到DataTable或从它里面删除,修改,或没有改变。
当DataTable刚产生时,所有的row都被标记为未修改的,修改了row的任何列后row会被标记为已修改的。
在SuppliersBLL类里我们首先将supplier的记录读进SuppliersDataTable里然后设置Address,City和Country列的值来更新指定的supplier的信息,见以下代码:
C#
publicboolUpdateSupplierAddress
(intsupplierID,stringaddress,stringcity,stringcountry)
{
Northwind.SuppliersDataTablesuppliers=
Adapter.GetSupplierBySupplierID(supplierID);
if(suppliers.Count==0)
//nomatchingrecordfound,returnfalse
returnfalse;
else
{
Northwind.SuppliersRowsupplier=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;
//UpdatethesupplierAddress-relatedinformation
introwsAffected=Adapter.Update(supplier);
//Returntrueifpreciselyonerowwasupdated,
//otherwisefalse
returnrowsAffected==1;
}
}
无论值是否有被修改,这段代码都将传入的address,city和country的值赋给SuppliersDataTable的SuppliersRow。
这个修改将使SuppliersRow的RowState属性被标记为已修改的。
当DAL的Update方法被调用时,它发现SupplierRow已经被修改了,因此向数据库发送UPDATE命令。
然而想象一下,我们为这个方法添加的代码仅仅在和已经存在的值不一样时才将传入的address,city和country的值赋给SuppliersRow。
在address,city和country没有修改的情况下,SupplierRow的RowState仍然标记为未改变。
这样的结果是当DAL的Update方法被调用时,SuppliersRow没有被修改,因此不会调用数据库。
使用以下的代码代替前面盲目的赋值:
C#
//OnlyassignthevaluestotheSupplierRow'scolumnvaluesiftheydiffer
if(address==null&&!
supplier.IsAddressNull())
supplier.SetAddressNull();
elseif((address!
=null&&supplier.IsAddressNull())||
(!
supplier.IsAddressNull()&&string.Compare(supplier.Address,address)!
=0))
supplier.Address=address;
if(city==null&&!
supplier.IsCityNull())
supplier.SetCityNull();
elseif((city!
=null&&supplier.IsCityNull())||
(!
supplier.IsCityNull()&&string.Compare(supplier.City,city)!
=0))
supplier.City=city;
if(country==null&&!
supplier.IsCountryNull())
supplier.SetCountryNull();
elseif((country!
=null&&supplier.IsCountryNull())||
(!
supplier.IsCountryNull()&&string.Compare(supplier.Country,country)!
=0))
supplier.Country=country;
增加了这些代码后,DAL的Update方法仅仅在更改过address相关的值的那些记录里才向数据库发送UPDATE命令。
当然我们也可以追踪传入的字段和数据库数据是否有区别,如果没有,就不需要调用DAL的Update方法。
这种方法在你使用直接的数据库命令时非常有效,因为直接的数据库命令不会检查SuppliersRow来决定是否需要调用数据库。
注意:
每次UpdateSupplierAddress方法被调用时,都会调用一次数据库来获取需要更新的记录的信息。
如果数据被修改,又要调用一次数据库来更新数据。
这个流程可以通过创建一个重载的UpdateSupplierAddress方法来优化,这个方法接受一个EmployeesDataTable,它包含BatchUpdate.aspx页的所有的修改。
然后它会调用一次数据库来获取Suppliers表里的所有记录。
在结果集里仅仅是被修改过的记录才能被更新。
总结
本章学习了如何创建一个完全可编辑的DataList。
通过它用户可以快速的修改多个supplier的address信息。
我们首先定义了编辑界面—address,city