共用方式為


批次刪除 (VB)

演講者:Scott Mitchell

下載 PDF

了解如何在單一操作中刪除多個資料庫記錄。 在使用者介面層中,我們將根據之前教學課程中建立的增強型 GridView 進行擴展。 在資料存取層中,我們將多個刪除操作包裝在一個交易中,以確保所有刪除成功或所有刪除都會回滾。

簡介

先前的教學課程探討如何使用完全可編輯的 GridView 建立批次編輯介面。 在使用者經常同時編輯多個記錄的情況下,批次編輯介面將需要的回傳和鍵盤到滑鼠上下文切換的次數更少,從而提高終端使用者的效率。 這種技術對於使用者經常一次性刪除多筆記錄的頁面同樣非常有用。

使用過線上電子郵件用戶端的任何人都已經熟悉最常見的批次刪除介面之一:網格中每行都有一個核取方塊,並帶有相應的「刪除所有選取的項目」按鈕 (見圖 1)。 這個教學課程相對較短,因為我們在之前的教學課程中已經完成了所有辛苦的工作,包括建立基於網頁的介面和實現一次性刪除多筆記錄的方法。 在「新增 GridView 核取方塊列」教學課程中,我們建立了一個包含核取方塊的 GridView 列。在「將資料庫修改包裝在交易中」教學課程中,我們在 BLL 中建立了一個方法,該方法將使用交易來刪除 ProductID 值的 List<T>。 在本教學課程中,我們將整合之前的經驗,建立一個可工作的批次刪除範例。

每行都將包含一個核取方塊

圖 1:每行都將包含一個核取方塊 (點擊查看完整圖片)

步驟 1:建立批次刪除介面

由於我們在「新增 GridView 核取方塊列」教學課程中已經建立了批次刪除介面,因此我們只需將其複製到 BatchDelete.aspx 即可,而不必從頭開始建立。 首先,打開 BatchData 資料夾中的 BatchDelete.aspx 頁面和 EnhancedGridView 資料夾中的 CheckBoxField.aspx 頁面。 從 CheckBoxField.aspx 頁面移至「來源」檢視,並複製 <asp:Content> 標籤之間的標記,如圖 2 所示。

將 CheckBoxField.aspx 的宣告式標記複製到剪貼簿

圖 2:將 CheckBoxField.aspx 的宣告式標記複製到剪貼簿 (點擊查看完整圖片)

接下來,前往 BatchDelete.aspx 中的來源檢視,並將剪貼簿的內容貼到 <asp:Content> 標籤內。 另外,將 CheckBoxField.aspx.vb 中的程式碼隱藏類別中的程式碼複製並貼上到 BatchDelete.aspx.vb 中的程式碼隱藏類別中 (DeleteSelectedProducts 按鈕的 Click 事件處理常式、ToggleCheckState 方法以及 CheckAllUncheckAll 按鈕的Click 事件處理常式)。 複製此內容後,BatchDelete.aspx 頁面的程式碼隱藏類別應包含以下程式碼:

Partial Class BatchData_BatchDelete
    Inherits System.Web.UI.Page
    Protected Sub DeleteSelectedProducts_Click(sender As Object, e As EventArgs) _
        Handles DeleteSelectedProducts.Click
        
        Dim atLeastOneRowDeleted As Boolean = False
        ' Iterate through the Products.Rows property
        For Each row As GridViewRow In Products.Rows
            ' Access the CheckBox
            Dim cb As CheckBox = row.FindControl("ProductSelector")
            If cb IsNot Nothing AndAlso cb.Checked Then
                ' Delete row! (Well, not really...)
                atLeastOneRowDeleted = True
                ' First, get the ProductID for the selected row
                Dim productID As Integer = _
                    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 ...
                ' Dim productAPI As New ProductsBLL
                ' productAPI.DeleteProduct(productID)
                '............................................
            End If
        Next
        ' Show the Label if at least one row was deleted...
        DeleteResults.Visible = atLeastOneRowDeleted
    End Sub
    Private Sub ToggleCheckState(ByVal checkState As Boolean)
        ' Iterate through the Products.Rows property
        For Each row As GridViewRow In Products.Rows
            ' Access the CheckBox
            Dim cb As CheckBox = row.FindControl("ProductSelector")
            If cb IsNot Nothing Then
                cb.Checked = checkState
            End If
        Next
    End Sub
    Protected Sub CheckAll_Click(sender As Object, e As EventArgs) _
        Handles CheckAll.Click
        ToggleCheckState(True)
    End Sub
    Protected Sub UncheckAll_Click(sender As Object, e As EventArgs) _
        Handles UncheckAll.Click
        ToggleCheckState(False)
    End Sub
End Class

複製宣告性標記和原始程式碼後,花點時間透過瀏覽器查看來測試 BatchDelete.aspx。 您應該會看到一個 GridView 列出了 GridView 中的前十個產品,每行都列出了產品的名稱、類別和價格以及一個核取方塊。 應有三個按鈕:全部選取、全部取消選取、刪除所選產品。 按一下「全部選取」按鈕將選取所有核取方塊,而「取消全部選取」將清除所有核取方塊。 點擊「刪除所選產品」會顯示一則訊息,其中列出了所選產品的 ProductID 值,但實際上並沒有刪除產品。

CheckBoxField.aspx 的介面已移至 BatchDeleting.aspx

圖 3CheckBoxField.aspx 的介面已移至 BatchDeleting.aspx (點擊查看完整圖片)

步驟 2:使用交易刪除選取的產品

將批次刪除介面成功複製到 BatchDeleting.aspx 後,剩下的就是更新程式碼,以便「刪除所選產品」按鈕使用 ProductsBLL 類別中的 DeleteProductsWithTransaction 方法刪除選取的產品。 此方法會新增在「在交易中包裝資料庫修改」教學課程中,接受 ProductID 值的 List(Of T) 作為其輸入,並刪除交易範圍內的每個對應的 ProductID

DeleteSelectedProducts 按鈕的 Click 事件處理常式目前使用以下 For Each 循環來迭代每個 GridView 行:

' Iterate through the Products.Rows property
For Each row As GridViewRow In Products.Rows
    ' Access the CheckBox
    Dim cb As CheckBox = row.FindControl("ProductSelector")
    If cb IsNot Nothing AndAlso cb.Checked Then
        ' Delete row! (Well, not really...)
        atLeastOneRowDeleted = True
        ' First, get the ProductID for the selected row
        Dim productID As Integer = _
            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 ...
        ' Dim productAPI As New ProductsBLL
        ' productAPI.DeleteProduct(productID)
        '............................................
    End If
Next

對於每一行,都會以程式設計方式參考 ProductSelector CheckBox Web 控制項。 如果選取該選項,則會從 DataKeys 集合中擷取行的 ProductID,並更新 DeleteResults 標籤的 Text 屬性以包含一則訊息,指示已選取該行進行刪除。

上面的程式碼實際上並沒有刪除任何記錄,因為對 ProductsBLL 類別的 Delete 方法的呼叫已被註解掉。如果套用此刪除邏輯,程式碼將刪除產品,但不會在原子操作中刪除。 也就是說,如果序列中的前幾次刪除成功,但後來的幾次刪除失敗 (可能由於違反外部索引鍵限制),則會擲回例外狀況,但已刪除的那些產品將保持刪除狀態。

為了確保原子性,我們需要使用 ProductsBLL 類別的 DeleteProductsWithTransaction 方法。 因為此方法接受 ProductID 值清單,所以我們需要先從網格編譯此清單,然後將其作為參數傳遞。 我們會先建立 Integer 類型的 List(Of T) 執行個體。 在 For Each 循環中,我們需要將所選產品的 ProductID 值新增至此 List(Of T)。 循環之後,此 List(Of T) 必須傳遞到 ProductsBLL 類別的 DeleteProductsWithTransaction 方法。 使用以下程式碼更新 DeleteSelectedProducts 按鈕的 Click 事件處理常式:

Protected Sub DeleteSelectedProducts_Click(sender As Object, e As EventArgs) _
    Handles DeleteSelectedProducts.Click
    
    ' Create a List to hold the ProductID values to delete
    Dim productIDsToDelete As New System.Collections.Generic.List(Of Integer)
    ' Iterate through the Products.Rows property
    For Each row As GridViewRow In Products.Rows
        ' Access the CheckBox
        Dim cb As CheckBox = CType(row.FindControl("ProductSelector"), CheckBox)
        If cb IsNot Nothing AndAlso cb.Checked Then
            ' Save the ProductID value for deletion
            ' First, get the ProductID for the selected row
            Dim productID As Integer = _
                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)
        End If
    Next
    ' Call the DeleteProductsWithTransaction method and show the Label 
    ' if at least one row was deleted...
    If productIDsToDelete.Count > 0 Then
        Dim productAPI As New ProductsBLL()
        productAPI.DeleteProductsWithTransaction(productIDsToDelete)
        DeleteResults.Visible = True
        ' Rebind the data to the GridView
        Products.DataBind()
    End If
End Sub

更新後的程式碼建立 Integer (productIDsToDelete) 類型的 List(Of T),並用要刪除的 ProductID 值填入。 For Each 循環結束後,如果至少選擇了一種產品,則呼叫 ProductsBLL 類別的 DeleteProductsWithTransaction 方法並傳遞此清單。 DeleteResults 標籤也會顯示,並且資料會重新繫結到 GridView (這樣新刪除的記錄就不會再作為行出現在網格中)。

圖 4 顯示了選擇刪除多行後的 GridView。 圖 5 顯示了點擊「刪除所選產品」按鈕後立即出現的畫面。 請注意,在圖 5 中,已刪除記錄的ProductID 值顯示在 GridView 下方的標籤中,而這些行不再出現在 GridView 中。

將刪除所選產品

圖 4:將刪除所選產品 (點擊查看完整圖片)

已刪除產品的 ProductID 值列在 GridView 下方

圖 5:已刪除產品的 ProductID 值列在 GridView 下方 (點擊查看完整圖片)

注意

若要測試 DeleteProductsWithTransaction 方法的原子性,請手動在 Order Details 表格中新增產品項目,然後嘗試刪除該產品 (以及其他產品)。 嘗試刪除具有關聯訂單的產品時,您將收到外部索引鍵約束衝突,但請注意其他選定產品的刪除是如何回溯的。

摘要

建立批次刪除介面涉及新增一個帶有核取方塊列的 GridView 和一個 Button Web 控制項,當按一下該控制項時,將作為單一原子操作刪除所有選取的行。 在本教學課程中,我們透過將前兩個教學課程「新增 GridView 核取方塊列」和「將資料庫修改包裝在交易中」中完成的工作拼湊在一起來建立這樣的介面。 在第一個教學課程中,我們建立了一個帶有一列核取方塊的 GridView,在後者中,我們在BLL 中實作了一個方法,當傳遞 ProductID 值的 List(Of T) 時,會在交易範圍內將它們全部刪除。

在下一個教學課程中,我們將建立一個用於執行批次插入的介面。

快樂程式!

關於作者

Scott Mitchell 是七本 ASP/ASP.NET 書籍的作者,也是 4GuysFromRolla.com 的創辦人,自 1998 年以來一直在使用 Microsoft 網路技術。 Scott 是一位獨立顧問、培訓師兼作家。 他的最新著作是 Sams Teach Yourself ASP.NET 2.0 in 24 Hours。 您可以透過電子郵件聯繫他:mitchell@4GuysFromRolla.com。 或者透過他的部落格與他聯繫,網址為 http://ScottOnWriting.NET

特別感謝

本教學課程系列已經過許多熱心的審閱者檢閱。 本教學課程的主要審閱者是 Hilton Giesenow 和 Teresa Murphy。 有興趣查看我即將發表的 MSDN 文章嗎? 如果是的話,請傳送郵件給我:mitchell@4GuysFromRolla.com。