在ASP.NET 2.0中操作數(shù)據(jù)之六十三:GridView實(shí)現(xiàn)批量刪除數(shù)據(jù)
導(dǎo)言:
在前面的教程,我們用GridView創(chuàng)建了一個(gè)批編輯界面。在用戶需要一次性編輯多條記錄的情況下,批編輯界面很有用。同理,當(dāng)用戶需要同時(shí)刪除多條記錄時(shí),該技術(shù)也很有用.
如果你使用過郵件系統(tǒng)的話,你應(yīng)該對(duì)這種最常見的批刪除界面很熟悉:界面里每一行都包含一個(gè)checkbox,此外,還有一個(gè)“Delete All Checked Items”按鈕(如圖1).本教程比較短,因?yàn)槲覀冊(cè)谇懊娴慕坛桃呀?jīng)完成大體的框架,在前面的第50章《為GridView控件添加Checkbox》里我們創(chuàng)建了一個(gè)包含一個(gè)checkboxes列的GridView控件;而在61章《在事務(wù)里對(duì)數(shù)據(jù)庫(kù)修改進(jìn)行封裝》里,我們?cè)贐LL業(yè)務(wù)邏輯層里創(chuàng)建了一個(gè)方法,該方法使用事務(wù)來刪除基于ProductID 的記錄.在本教程,我們將整合這些內(nèi)容來創(chuàng)建一個(gè)處理批刪除的示例.

圖1:每一行都包含一個(gè)Checkbox
第一步:創(chuàng)建批刪除界面
由于我們?cè)诘?2章已經(jīng)創(chuàng)建了一個(gè)批刪除界面,因此我們可以簡(jiǎn)單的將其拷貝到BatchDelete.aspx頁(yè)面。首先,打開BatchData文件夾里的BatchDelete.aspx頁(yè)面,以及EnhancedGridView文件夾里的CheckBoxField.aspx頁(yè)面。在CheckBoxField.aspx頁(yè)面,切換到Source模式,將<asp:Content>標(biāo)簽里的代碼進(jìn)行復(fù)制.

圖2:復(fù)制CheckBoxField.aspx頁(yè)面里的聲明代碼
然后,切換到BatchDelete.aspx頁(yè)面的Source模式,將代碼粘貼到<asp:Content>標(biāo)簽里.同理,將CheckBoxField.aspx.cs里面的后臺(tái)代碼拷貝到BatchDelete.aspx.cs里.(具體來說,就是將DeleteSelectedProducts按鈕的Click event事件、ToggleCheckState方法、CheckAll 和 UncheckAll按鈕的Click event事件)。完成拷貝后,BatchDelete.aspx頁(yè)面的后臺(tái)代碼類應(yīng)該包含下面的代碼:
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);
}
}
完成上述工作后,花幾分鐘在瀏覽器里測(cè)試該頁(yè)面.你應(yīng)該首先看到一個(gè)GridView控件列出了前10個(gè)產(chǎn)品,每行列出了產(chǎn)品的name, category,price以及一個(gè)checkbox. 同時(shí)應(yīng)該有3個(gè)按鈕“Check All”, “Uncheck All”和“Delete Selected Products”.點(diǎn)“Check All”按鈕將會(huì)選中所有的checkboxes;而“Uncheck All”按鈕將釋放所有的
checkboxes;點(diǎn)“Delete Selected Products”的話將顯示一個(gè)消息,列出選中的產(chǎn)品的ProductID值,不過并不會(huì)真的刪除產(chǎn)品.

圖3:CheckBoxField.aspx頁(yè)面的界面搬到了BatchDeleting.aspx頁(yè)面
第二步:在事務(wù)里刪除選中的產(chǎn)品
完成界面后,剩下的事情是更新代碼,以便當(dāng)點(diǎn)擊“Delete Selected Products”按鈕時(shí),使用ProductsBLL class類里的DeleteProductsWithTransaction方法來刪除選中的產(chǎn)品.該方法是我們?cè)诘?1章《在事務(wù)里對(duì)數(shù)據(jù)庫(kù)修改進(jìn)行封裝》里添加的,它接受一系列的ProductID值,然后在一個(gè)事務(wù)里將刪除對(duì)應(yīng)的ProductID的記錄.
DeleteSelectedProducts按鈕的Click事件目前使用的foreach循環(huán)如下:
// 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);
//............................................
}
}
對(duì)每行而言,編程引用ProductSelector CheckBox控件,如果它被選中,從DataKeys collection集獲取該產(chǎn)品的ProductID值,然后更新DeleteResults控件的Text屬性以顯示要?jiǎng)h除該行.
上面的代碼并不會(huì)真的刪除任何的記錄,因?yàn)樵赑roductsBLL class類里我們只是注釋出了如何使用Delete方法。 不過就算實(shí)際地運(yùn)用了這些刪除邏輯,這些代碼雖然可以刪除產(chǎn)品但沒有運(yùn)用原子操作.也就是說,如果按順序?qū)︻^幾個(gè)產(chǎn)品刪除成功,如果接下來的某個(gè)產(chǎn)品刪除失敗(比如可能是違背里外鍵約束),那么將拋出一個(gè)異常,但是前面的刪除操作并不會(huì)回滾.
為了保證使用原子操作,我們將轉(zhuǎn)為使用ProductsBLLclass類的DeleteProductsWithTransaction method方法.由于該方法接受一系列的ProductID值,
我們首先需要編譯這一系列的值,再將其作為參數(shù)傳遞出去.我們首先創(chuàng)建一個(gè)int類型的List<T>的實(shí)例,在foreach循環(huán)里我們需要將產(chǎn)品的ProductID值添加給List<T>,結(jié)束循環(huán)后,List<T>將傳遞給ProductsBLL class類的DeleteProductsWithTransaction method方法,用下面的代碼對(duì)DeleteSelectedProducts按鈕的Click事件處理器進(jìn)行更新:
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();
}
}
上述代碼創(chuàng)建了一個(gè)int類型的List<T>(也就是productIDsToDelete),并用ProductID值對(duì)其進(jìn)行填充,foreach循環(huán)結(jié)束后,如果至少選中了一個(gè)產(chǎn)品,將調(diào)用ProductsBLL 類的DeleteProductsWithTransaction method方法,并傳遞該List。名為DeleteResults的Label控件也將顯示出來;數(shù)據(jù)重新綁定到GridView(自然,剛刪除掉的記錄將不會(huì)顯示出來).
圖4里,我們選擇幾個(gè)產(chǎn)品以刪除;圖5顯示的是點(diǎn)擊“Delete Selected Products”按鈕后的界面.注意,在Label控件里顯示的已經(jīng)刪除的產(chǎn)品的ProductID值,而這些產(chǎn)品已經(jīng)刪除掉了,并沒有出現(xiàn)在GridView控件里.

圖4:選中的產(chǎn)品將被刪除

圖5:被刪除產(chǎn)品的ProductID值出現(xiàn)的GridView下面的Label控件里
注意:為驗(yàn)證DeleteProductsWithTransaction method方法的原子操作,你可以為某個(gè)產(chǎn)品在Order Details表里手動(dòng)添加一個(gè)條目,然后嘗試刪除該產(chǎn)品(當(dāng)然與其它產(chǎn)品一起刪除).這將會(huì)違背外鍵約束,注意對(duì)其它產(chǎn)品的刪除操作是如何回滾的.
總結(jié):
創(chuàng)建一個(gè)批刪除界面的話,我們需要?jiǎng)?chuàng)建一個(gè)包含checkboxes列的GridView控件,以及Button Web控件。當(dāng)點(diǎn)擊該按鈕時(shí),我們將刪除多個(gè)產(chǎn)品當(dāng)作一個(gè)單一原子操作.在本文,我們創(chuàng)建的界面整合了以前的2個(gè)章節(jié)的內(nèi)容.
在下一篇,我們考察如何創(chuàng)建一個(gè)批插入的界面
祝編程快樂!
作者簡(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有所幫助。
相關(guān)文章
解讀ASP.NET 5 & MVC6系列教程(6):Middleware詳解
這篇文章主要介紹了Middleware詳解,需要的朋友可以參考下2016-06-06
Microsoft .Net Remoting系列教程之三:Remoting事件處理全接觸
本文主要講解.Net Remoting中的Remoting事件處理,需要的朋友可以參考下。2016-05-05
在ASP.NET 2.0中操作數(shù)據(jù)之二十八:GridView里的Button
本文主要介紹ASP.NET 2.0在GridView,DetailsView,FormView都可以包含Buttons,LinkButtons,或ImageButtons.這些button被點(diǎn)擊時(shí),并激發(fā)FormView和DetailsView的ItemCommand事件,GridView的RowCommand事件,根據(jù)CommandName的值來判斷哪個(gè)button被點(diǎn)擊了,執(zhí)行相應(yīng)的代碼。2016-05-05
在ASP.NET 2.0中操作數(shù)據(jù)之四十二:DataList和Repeater數(shù)據(jù)排序(一)
本文主要介紹利用ObjectDataSource的Selecting事件進(jìn)行DataList和Repeater數(shù)據(jù)排序的方法,DropDownList隱式的為我們將sort expression 和 direction保存在它的view state里,進(jìn)行分頁(yè)時(shí)從view state中取出條件進(jìn)行排序。2016-05-05
解讀ASP.NET 5 & MVC6系列教程(9):日志框架
這篇文章主要介紹了ASP.NET 5 日志框架,通過基于接口的編程機(jī)制和DI依賴注入機(jī)制,我們可以很容易實(shí)現(xiàn)第三方日志provider的擴(kuò)展,從而將日志記錄到我們想記錄的任意地方,需要的朋友可以參考下2016-06-06
ASP.NET MVC4入門教程(二):添加一個(gè)控制器
本文對(duì)MVC模式(模型-視圖-控制器)做了簡(jiǎn)單的介紹,并演示如何添加一個(gè)控制器。2016-04-04
.Net?Core服務(wù)治理Consul使用服務(wù)發(fā)現(xiàn)
Consul是HashiCorp公司推出的開源工具,Consul由Go語(yǔ)言開發(fā),部署起來非常容易,只需要極少的可執(zhí)行程序和配置文件,具有綠色、輕量級(jí)的特點(diǎn)。Consul是分布式的、高可用的、?可橫向擴(kuò)展的用于實(shí)現(xiàn)分布式系統(tǒng)的服務(wù)發(fā)現(xiàn)與配置2022-01-01
在ASP.NET 2.0中操作數(shù)據(jù)之十九:給編輯和新增界面增加驗(yàn)證控件
本文主要介紹如何對(duì)GridView和DetailsView的新增、編輯功能進(jìn)行完善,將原來自動(dòng)生成的綁定列轉(zhuǎn)換為模板列,進(jìn)而增加驗(yàn)證控件,有助于更多了解ASP.NET 2.0中新的特性。2016-05-05

