Batch-borttagning (VB)

av Scott Mitchell

Ladda ned PDF

Lär dig hur du tar bort flera databasposter i en enda åtgärd. I användargränssnittsskiktet bygger vi på en förbättrad GridView som skapats i en tidigare självstudie. I dataåtkomstlagret omsluter vi flera borttagningsåtgärder i en transaktion för att säkerställa att alla borttagningar lyckas eller att alla borttagningar återställs.

Inledning

I den föregående självstudien utforskades hur du skapar ett batchredigeringsgränssnitt med hjälp av ett fullständigt redigerbart GridView. I situationer där användare ofta redigerar många poster samtidigt kräver ett batchredigeringsgränssnitt mycket färre postbacks och kontextväxlar från tangentbord till mus, vilket förbättrar slutanvändarens effektivitet. Den här tekniken är lika användbar för sidor där det är vanligt att användare tar bort många poster på en och samma resa.

Alla som har använt en e-postklient online är redan bekant med ett av de vanligaste batchborttagningsgränssnitten: en kryssruta i varje rad i ett rutnät med motsvarande knappen Ta bort alla markerade objekt (se bild 1). Den här handledningen är ganska kort eftersom vi redan har gjort allt det tunga arbetet i tidigare handledningar för att skapa både det webbaserade gränssnittet och en metod för att ta bort en serie poster som en enda atomisk operation. I självstudien Lägga till en GridView-kolumn med kryssrutor skapade vi en GridView med en kolumn med kryssrutor och i självstudiekursen Omsluta databasändringar i en transaktion skapade vi en metod i BLL som skulle använda en transaktion för att ta bort en List<T> med ProductID värden. I den här självstudien kommer vi att bygga vidare på och sammansmälta våra tidigare erfarenheter för att skapa ett fungerande exempel på batchborttagning.

Varje rad innehåller en kryssruta

Bild 1: Varje rad innehåller en kryssruta (Klicka om du vill visa en bild i full storlek)

Steg 1: Skapa batchborttagningsgränssnittet

Eftersom vi redan har skapat batchborttagningsgränssnittet i självstudien Lägga till en GridView-kolumn med kryssrutor, kan vi helt enkelt kopiera den till BatchDelete.aspx istället för att skapa den från grunden. Börja med att öppna sidan BatchDelete.aspx i BatchData mappen och CheckBoxField.aspx sidan i EnhancedGridView mappen. Från sidan CheckBoxField.aspx går du till källvyn och kopierar pålägget mellan taggarna <asp:Content> enligt bild 2.

Kopiera deklarativ markering av CheckBoxField.aspx till Urklipp

Bild 2: Kopiera deklarationskod för CheckBoxField.aspx till Urklippet (Klicka för att visa bilden i full storlek)

Gå sedan till källvyn i BatchDelete.aspx och klistra in innehållet från urklippet i <asp:Content> taggarna. Kopiera och klistra också in koden från code-behind-klassen i CheckBoxField.aspx.vb till code-behind-klassen i BatchDelete.aspx.vb (händelsehanteraren för knappen DeleteSelectedProductsClick, ToggleCheckState-metoden, och händelsehanterarna för Click och CheckAll-knapparna). När du har kopierat över det här innehållet ska BatchDelete.aspx-sidans code-behind-klass innehålla följande kod:

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

När du har kopierat över deklarativ kod och källkod tar du en stund att testa BatchDelete.aspx genom att visa den via en webbläsare. Du bör se en GridView-lista över de första tio produkterna i en GridView med varje rad som visar produktens namn, kategori och pris tillsammans med en kryssruta. Det bör finnas tre knappar: Markera Alla, Avmarkera Alla och Ta bort markerade produkter. Om du klickar på knappen Markera alla markeras alla kryssrutor, medan Avmarkera alla avmarkerar alla kryssrutor. När du klickar på Ta bort markerade produkter visas ett meddelande som visar ProductID värdena för de valda produkterna, men som inte tar bort produkterna.

Gränssnittet från CheckBoxField.aspx har flyttats till BatchDeleting.aspx

Bild 3: Gränssnittet från CheckBoxField.aspx har flyttats till BatchDeleting.aspx (Klicka om du vill visa en bild i full storlek)

Steg 2: Ta bort de kontrollerade produkterna med hjälp av transaktioner

När batchborttagningsgränssnittet har kopierats till BatchDeleting.aspxär allt som återstår att uppdatera koden så att knappen Ta bort markerade produkter tar bort de kontrollerade produkterna med hjälp av DeleteProductsWithTransaction metoden i ProductsBLL klassen. Den här metoden, som läggs till i handledningen Omsluta databasändringar i en transaktion, accepterar som indata en samling av List(Of T) värden och tar bort varje motsvarande ProductID inom omfånget för en transaktion.

Händelsehanteraren DeleteSelectedProducts för Button Click använder för närvarande följande For Each loop för att iterera genom varje GridView-rad:

' 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

För varje rad hänvisas ProductSelector CheckBox webbkontroll programmatiskt. Om den är markerad hämtas raden ProductID från DataKeys-samlingen och egenskapen för etiketten DeleteResults har uppdaterats Text så att den innehåller ett meddelande som anger att raden har valts för borttagning.

Koden ovan tar faktiskt inte bort några poster eftersom anropet till ProductsBLL klassens Delete-metod har kommenterats ut. Om den här borttagningslogiken skulle tillämpas skulle koden ta bort produkterna men inte inom en atomisk operation. Om de första borttagningarna i sekvensen lyckades, men ett senare misslyckades (kanske på grund av en överträdelse av begränsningen för främmande nyckel), skulle ett undantag kastas, men de produkter som redan har tagits bort skulle förbli borttagna.

För att säkerställa atomitet måste vi i stället använda ProductsBLL metoden class s DeleteProductsWithTransaction . Eftersom den här metoden accepterar en lista med ProductID värden måste vi först kompilera den här listan från rutnätet och sedan skicka den som en parameter. Först skapar vi en instans av typen List(Of T)Integer. I loopen For Each måste vi lägga till värdena för de valda produkterna ProductID i denna List(Of T). Efter loopen måste detta List(Of T) skickas till ProductsBLL klassens DeleteProductsWithTransaction -metod. DeleteSelectedProducts Uppdatera knappens Click händelsehanterare med följande kod:

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

Den uppdaterade koden skapar en List(Of T) av typen Integer (productIDsToDelete) och fyller den med de värden som ProductID ska tas bort. Efter For Each-loopen anropas ProductsBLL-klassens DeleteProductsWithTransaction-metod och skickas den här listan om det finns minst en vald produkt. Etiketten DeleteResults visas också och data återställs till GridView (så att de nyligen borttagna posterna inte längre visas som rader i rutnätet).

Bild 4 visar GridView när ett antal rader har valts för borttagning. Bild 5 visar skärmen direkt efter att knappen Ta bort markerade produkter har klickats på. Observera att värdena för de borttagna posterna ProductID i bild 5 visas i etiketten under GridView och att dessa rader inte längre finns i GridView.

De markerade produkterna tas bort

Bild 4: De markerade produkterna tas bort (klicka om du vill visa en bild i full storlek)

ProductID-värdena för borttagna produkter visas under GridView

Bild 5: Värdena för borttagna produkter ProductID visas under GridView (klicka om du vill visa en bild i full storlek)

Anmärkning

Om du vill testa DeleteProductsWithTransaction metodens atomitet lägger du manuellt till en post för en produkt i Order Details tabellen och försöker sedan ta bort produkten (tillsammans med andra). Du kommer att få en överträdelse av främmande nyckelbegränsning när du försöker ta bort produkten med en associerad order, men observera hur de andra valda produkternas borttagningar rullas tillbaka.

Sammanfattning

När du skapar ett batchborttagningsgränssnitt måste du lägga till en GridView med en kolumn med kryssrutor och en knappwebbkontroll som när du klickar på den tar bort alla markerade rader som en enda atomisk åtgärd. I den här självstudien har vi skapat ett sådant gränssnitt genom att sammanställa arbete som utförts i två tidigare självstudier, lägga till en GridView-kolumn med kryssrutor och omsluta databasändringar i en transaktion. I den första självstudien skapade vi en GridView med en kolumn med kryssrutor och i den senare självstudien implementerade vi en metod i BLL:n som, när den skickades en lista av List(Of T) värden, tog bort dem alla inom omfånget för en transaktion.

I nästa handledning skapar vi ett gränssnitt för att utföra batchinfogningar.

Lycka till med programmerandet!

Om författaren

Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.

Särskilt tack till

Den här självstudieserien granskades av många användbara granskare. Huvudgranskare för den här handledningen var Hilton Giesenow och Teresa Murphy. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.