在ASP.NET 2.0中操作数据之六十三:GridView实现批量删除数据
导言:
在前面的教程,我们用gridview创建了一个批编辑界面。在用户需要一次性编辑多条记录的情况下,批编辑界面很有用。同理,当用户需要同时删除多条记录时,该技术也很有用.
如果你使用过邮件系统的话,你应该对这种最常见的批删除界面很熟悉:界面里每一行都包含一个checkbox,此外,还有一个“delete all checked items”按钮(如图1).本教程比较短,因为我们在前面的教程已经完成大体的框架,在前面的第50章《为gridview控件添加checkbox》里我们创建了一个包含一个checkboxes列的gridview控件;而在61章《》里,我们在bll业务逻辑层里创建了一个方法,该方法使用事务来删除基于productid 的记录.在本教程,我们将整合这些内容来创建一个处理批删除的示例.
图1:每一行都包含一个checkbox
第一步:创建批删除界面
由于我们在第52章已经创建了一个批删除界面,因此我们可以简单的将其拷贝到batchdelete.aspx页面。首先,打开batchdata文件夹里的batchdelete.aspx页面,以及enhancedgridview文件夹里的checkboxfield.aspx页面。在checkboxfield.aspx页面,切换到source模式,将<asp:content>标签里的代码进行复制.
图2:复制checkboxfield.aspx页面里的声明代码
然后,切换到batchdelete.aspx页面的source模式,将代码粘贴到<asp:content>标签里.同理,将checkboxfield.aspx.cs里面的后台代码拷贝到batchdelete.aspx.cs里.(具体来说,就是将deleteselectedproducts按钮的click event事件、togglecheckstate方法、checkall 和 uncheckall按钮的click event事件)。完成拷贝后,batchdelete.aspx页面的后台代码类应该包含下面的代码:
using system; using system.data; using system.configuration; using system.collections; using system.web; using system.web.security; using system.web.ui; using system.web.ui.webcontrols; using system.web.ui.webcontrols.webparts; using system.web.ui.htmlcontrols; public partial class batchdata_batchdelete : system.web.ui.page { protected void deleteselectedproducts_click(object sender, eventargs e) { bool atleastonerowdeleted = false; // iterate through the products.rows property foreach (gridviewrow row in products.rows) { // access the checkbox checkbox cb = (checkbox)row.findcontrol("productselector"); if (cb != null && cb.checked) { // delete row! (well, not really...) atleastonerowdeleted = true; // first, get the productid for the selected row int productid = convert.toint32(products.datakeys[row.rowindex].value); // "delete" the row deleteresults.text += string.format ("this would have deleted productid {0}<br />", productid); //... to actually delete the product, use ... //productsbll productapi = new productsbll(); //productapi.deleteproduct(productid); //............................................ } } // show the label if at least one row was deleted... deleteresults.visible = atleastonerowdeleted; } private void togglecheckstate(bool checkstate) { // iterate through the products.rows property foreach (gridviewrow row in products.rows) { // access the checkbox checkbox cb = (checkbox)row.findcontrol("productselector"); if (cb != null) cb.checked = checkstate; } } protected void checkall_click(object sender, eventargs e) { togglecheckstate(true); } protected void uncheckall_click(object sender, eventargs e) { togglecheckstate(false); } }
完成上述工作后,花几分钟在浏览器里测试该页面.你应该首先看到一个gridview控件列出了前10个产品,每行列出了产品的name, category,price以及一个checkbox. 同时应该有3个按钮“check all”, “uncheck all”和“delete selected products”.点“check all”按钮将会选中所有的checkboxes;而“uncheck all”按钮将释放所有的
checkboxes;点“delete selected products”的话将显示一个消息,列出选中的产品的productid值,不过并不会真的删除产品.
图3:checkboxfield.aspx页面的界面搬到了batchdeleting.aspx页面
第二步:在事务里删除选中的产品
完成界面后,剩下的事情是更新代码,以便当点击“delete selected products”按钮时,使用productsbll class类里的deleteproductswithtransaction方法来删除选中的产品.该方法是我们在第61章《》里添加的,它接受一系列的productid值,然后在一个事务里将删除对应的productid的记录.
deleteselectedproducts按钮的click事件目前使用的foreach循环如下:
// iterate through the products.rows property foreach (gridviewrow row in products.rows) { // access the checkbox checkbox cb = (checkbox)row.findcontrol("productselector"); if (cb != null && cb.checked) { // delete row! (well, not really...) atleastonerowdeleted = true; // first, get the productid for the selected row int productid = convert.toint32(products.datakeys[row.rowindex].value); // "delete" the row deleteresults.text += string.format ("this would have deleted productid {0}<br />", productid); //... to actually delete the product, use ... //productsbll productapi = new productsbll(); //productapi.deleteproduct(productid); //............................................ } }
对每行而言,编程引用productselector checkbox控件,如果它被选中,从datakeys collection集获取该产品的productid值,然后更新deleteresults控件的text属性以显示要删除该行.
上面的代码并不会真的删除任何的记录,因为在productsbll class类里我们只是注释出了如何使用delete方法。 不过就算实际地运用了这些删除逻辑,这些代码虽然可以删除产品但没有运用原子操作.也就是说,如果按顺序对头几个产品删除成功,如果接下来的某个产品删除失败(比如可能是违背里外键约束),那么将抛出一个异常,但是前面的删除操作并不会回滚.
为了保证使用原子操作,我们将转为使用productsbllclass类的deleteproductswithtransaction method方法.由于该方法接受一系列的productid值,
我们首先需要编译这一系列的值,再将其作为参数传递出去.我们首先创建一个int类型的list<t>的实例,在foreach循环里我们需要将产品的productid值添加给list<t>,结束循环后,list<t>将传递给productsbll class类的deleteproductswithtransaction method方法,用下面的代码对deleteselectedproducts按钮的click事件处理器进行更新:
protected void deleteselectedproducts_click(object sender, eventargs e) { // create a list to hold the productid values to delete system.collections.generic.list<int> productidstodelete = new system.collections.generic.list<int>(); // iterate through the products.rows property foreach (gridviewrow row in products.rows) { // access the checkbox checkbox cb = (checkbox)row.findcontrol("productselector"); if (cb != null && cb.checked) { // save the productid value for deletion // first, get the productid for the selected row int productid = convert.toint32(products.datakeys[row.rowindex].value); // add it to the list... productidstodelete.add(productid); // add a confirmation message deleteresults.text += string.format ("productid {0} has been deleted<br />", productid); } } // call the deleteproductswithtransaction method and show the label // if at least one row was deleted... if (productidstodelete.count > 0) { productsbll productapi = new productsbll(); productapi.deleteproductswithtransaction(productidstodelete); deleteresults.visible = true; // rebind the data to the gridview products.databind(); } }
上述代码创建了一个int类型的list<t>(也就是productidstodelete),并用productid值对其进行填充,foreach循环结束后,如果至少选中了一个产品,将调用productsbll 类的deleteproductswithtransaction method方法,并传递该list。名为deleteresults的label控件也将显示出来;数据重新绑定到gridview(自然,刚删除掉的记录将不会显示出来).
图4里,我们选择几个产品以删除;图5显示的是点击“delete selected products”按钮后的界面.注意,在label控件里显示的已经删除的产品的productid值,而这些产品已经删除掉了,并没有出现在gridview控件里.
图4:选中的产品将被删除
图5:被删除产品的productid值出现的gridview下面的label控件里
注意:为验证deleteproductswithtransaction method方法的原子操作,你可以为某个产品在order details表里手动添加一个条目,然后尝试删除该产品(当然与其它产品一起删除).这将会违背外键约束,注意对其它产品的删除操作是如何回滚的.
总结:
创建一个批删除界面的话,我们需要创建一个包含checkboxes列的gridview控件,以及button web控件。当点击该按钮时,我们将删除多个产品当作一个单一原子操作.在本文,我们创建的界面整合了以前的2个章节的内容.
在下一篇,我们考察如何创建一个批插入的界面
祝编程快乐!
作者简介
本系列教程作者 scott mitchell,著有六本asp/asp.net方面的书,是4guysfromrolla.com的创始人,自1998年以来一直应用 微软web技术。大家可以点击查看全部教程《[翻译]scott mitchell 的asp.net 2.0数据教程》,希望对大家的学习asp.net有所帮助。