Udostępnij za pomocą


Usuwanie zbiorcze (VB)

Autor : Scott Mitchell

Pobierz plik PDF

Dowiedz się, jak usunąć wiele rekordów bazy danych w ramach jednej operacji. W warstwie interfejsu użytkownika bazujemy na ulepszonym widoku siatki utworzonym we wcześniejszym samouczku. W warstwie dostępu do danych opakowujemy wiele operacji usuwania w ramach transakcji, aby upewnić się, że wszystkie operacje usuwania kończą się powodzeniem lub wszystkie usunięcia zostaną wycofane.

Wprowadzenie

W poprzednim samouczku przedstawiono sposób tworzenia interfejsu edytowania wsadowego przy użyciu w pełni edytowalnego elementu GridView. W sytuacjach, gdy użytkownicy często edytują wiele rekordów jednocześnie, interfejs edycji wsadowej będzie wymagał znacznie mniej przesyłania danych zwrotnych i przełączania kontekstu z klawiatury na mysz, co poprawia wydajność użytkownika końcowego. Ta technika jest podobnie przydatna w przypadku stron, na których użytkownicy często usuwają wiele rekordów w jednym miejscu.

Każda osoba, która korzystała z klienta poczty e-mail online, zna już jeden z najbardziej typowych interfejsów usuwania partii: pole wyboru w każdym wierszu w siatce z odpowiednim przyciskiem Usuń wszystkie zaznaczone elementy (zobacz Rysunek 1). Ten samouczek jest dość krótki, ponieważ wykonaliśmy już całą ciężką pracę w poprzednich samouczkach podczas tworzenia zarówno interfejsu internetowego, jak i metody usuwania serii rekordów jako pojedynczej operacji niepodzielnej. W samouczku Dodawanie kolumny GridView pól wyboru utworzyliśmy GridView z kolumną pól wyboru, a w samouczku Zawijanie modyfikacji bazy danych w ramach transakcji utworzyliśmy metodę w warstwie biznesowej (BLL), która będzie używać transakcji do usuwania List<T>ProductID wartości. W tym samouczku wykorzystamy i połączymy nasze wcześniejsze doświadczenia, aby stworzyć działający przykład usuwania hurtowego.

Każdy wiersz zawiera pole wyboru

Rysunek 1. Każdy wiersz zawiera pole wyboru (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Krok 1. Tworzenie interfejsu usuwania partii

Ponieważ w samouczku Dodawanie kolumny pól wyboru w widoku siatki utworzyliśmy już interfejs do usuwania wsadowego, możemy go po prostu skopiować do BatchDelete.aspx, zamiast tworzyć go od podstaw. Zacznij od otwarcia strony BatchDelete.aspx w folderze BatchData oraz strony CheckBoxField.aspx w folderze EnhancedGridView. Na stronie CheckBoxField.aspx przejdź do widoku źródła i skopiuj znaczniki między tagami <asp:Content>, jak pokazano na rysunku 2.

Skopiuj deklaratywny znacznik CheckBoxField.aspx do Schowka

Rysunek 2. Kopiowanie deklaratywnego znacznika CheckBoxField.aspx do Schowka (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Następnie przejdź do widoku Źródło w BatchDelete.aspx i wklej zawartość schowka w tagach <asp:Content>. Skopiuj i wklej kod z klasy "code-behind" z CheckBoxField.aspx.vb do klasy "code-behind" w BatchDelete.aspx.vb (procedura obsługi zdarzenia przycisku DeleteSelectedProducts, metoda Click oraz procedury obsługi zdarzeń dla przycisków ToggleCheckState i Click). Po skopiowaniu tej zawartości BatchDelete.aspx klasa s code-behind strony powinna zawierać następujący 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

Po skopiowaniu znaczników deklaracyjnych i kodu źródłowego, poświęć chwilę na sprawdzenie BatchDelete.aspx za pomocą przeglądarki. Powinieneś zobaczyć element GridView, który zawiera listę pierwszych dziesięciu produktów, z każdym wierszem listy zawierającym nazwę, kategorię i cenę produktu wraz z polem wyboru. Powinny istnieć trzy przyciski: Zaznacz wszystko, Odznacz wszystko i Usuń wybrane produkty. Kliknięcie przycisku Zaznacz wszystko powoduje zaznaczenie wszystkich pól wyboru, podczas gdy przycisk Usuń zaznaczenie wszystkich usuwa zaznaczenie wszystkich pól wyboru. Kliknięcie pozycji Usuń wybrane produkty powoduje wyświetlenie komunikatu z listą ProductID wartości wybranych produktów, ale w rzeczywistości nie powoduje usunięcia produktów.

Interfejs z CheckBoxField.aspx został przeniesiony do BatchDeleting.aspx

Rysunek 3. Interfejs z CheckBoxField.aspx został przeniesiony do BatchDeleting.aspx (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Krok 2. Usuwanie zaznaczonych produktów przy użyciu transakcji

Po pomyślnym skopiowaniu interfejsu usuwania wsadowego do BatchDeleting.aspx, pozostało tylko zaktualizować kod, aby przycisk Usuń wybrane produkty usuwał zaznaczone produkty, używając metody DeleteProductsWithTransaction w klasie ProductsBLL. Ta metoda, dodana w samouczku Zawijanie modyfikacji bazy danych w ramach transakcji, przyjmuje List(Of T)ProductID jako dane wejściowe i usuwa każdy odpowiadający ProductID w zakresie transakcji.

Proces obsługi zdarzeń dla przycisku DeleteSelectedProducts używa obecnie następującej pętli Click do iterowania po każdym wierszu w GridView For Each.

' 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

Dla każdego wiersza kontrolka ProductSelector sieci Web CheckBox jest programowo przywoływana. Jeśli jest zaznaczone, wiersz ProductID jest pobierany z kolekcji DataKeys, a właściwość etykiety DeleteResults jest uaktualniana, żeby uwzględnić wiadomość informującą, że wiersz został wybrany do usunięcia.

Powyższy kod nie usuwa żadnych rekordów, ponieważ wywołanie ProductsBLL metody klasy s Delete jest oznaczane jako komentarz. Gdyby ta logika usuwania została zastosowana, kod usunąłby produkty, ale nie w ramach operacji niepodzielnej. Oznacza to, że jeśli pierwsze kilka operacji usuwania w sekwencji zakończyło się pomyślnie, ale późniejsza nie powiodła się (być może z powodu naruszenia ograniczenia klucza obcego), wyjątek zostanie zgłoszony, ale usunięte produkty pozostaną usunięte.

Aby zapewnić niepodzielność, musimy zamiast tego użyć ProductsBLL metody s DeleteProductsWithTransaction klasy. Ponieważ ta metoda akceptuje listę ProductID wartości, musimy najpierw skompilować tę listę z siatki, a następnie przekazać ją jako parametr. Najpierw utworzymy wystąpienie List(Of T) typu Integer. W obrębie pętli musimy dodać wartości wybranych produktów For Each do tego ProductID. Po zakończeniu pętli należy przekazać ten List(Of T) do metody ProductsBLL klasy DeleteProductsWithTransaction. Zaktualizuj procedurę obsługi zdarzeń DeleteSelectedProducts przycisku Click przy użyciu następującego kodu:

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

Zaktualizowany kod tworzy List(Of T) typu Integer (productIDsToDelete) i uzupełnia go wartościami ProductID przeznaczonymi do usunięcia. Po pętli For Each, jeśli zaznaczono co najmniej jeden produkt, metoda klasy ProductsBLL jest wywoływana DeleteProductsWithTransaction i przekazuje tę listę. Etykieta DeleteResults jest również wyświetlana, a dane są ponownie powiązane z widokiem siatki (tak aby nowo usunięte rekordy nie pojawiały się już jako wiersze w widoku siatki).

Rysunek 4 przedstawia element GridView po wybraniu kilku wierszy do usunięcia. Rysunek 5 przedstawia ekran natychmiast po kliknięciu przycisku Usuń wybrane produkty. Należy pamiętać, że na rysunku 5 wartości rekordów usuniętych są wyświetlane w etykiecie pod GridView, a te wiersze nie znajdują się już w kontrolce GridView.

Wybrane produkty zostaną usunięte

Rysunek 4. Wybrane produkty zostaną usunięte (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Wartości ProductID usuniętych produktów są wyświetlane pod GridView

Rysunek 5. Usunięte wartości produktów ProductID są wyświetlane pod kontrolką GridView (kliknij, aby wyświetlić obraz pełnowymiarowy)

Uwaga / Notatka

Aby przetestować atomiczność metody DeleteProductsWithTransaction, ręcznie dodaj wpis dla produktu w tabeli Order Details, a następnie spróbuj usunąć ten produkt (wraz z innymi). Podczas próby usunięcia produktu ze skojarzonym zamówieniem otrzymasz naruszenie ograniczenia klucza obcego, ale zwróć uwagę na sposób wycofania innych wybranych produktów.

Podsumowanie

Utworzenie interfejsu usuwania wsadowego obejmuje dodanie kontrolki GridView z kolumną przycisków wyboru oraz kontrolki przycisku internetowego, która po kliknięciu spowoduje usunięcie wszystkich zaznaczonych wierszy jako pojedynczej operacji atomowej. W tym samouczku utworzyliśmy taki interfejs, łącząc pracę wykonaną w dwóch poprzednich samouczkach: Dodawanie kolumny GridView pól wyboru i zawijanie modyfikacji bazy danych w ramach transakcji. W pierwszym samouczku utworzyliśmy GridView z kolumną pól wyboru, a w drugim zaimplementowaliśmy metodę w warstwie logiki biznesowej (BLL), która po przekazaniu zbioru wartości List(Of T)ProductID skasowała je wszystkie w ramach transakcji.

W następnym samouczku utworzymy interfejs do wsadowego wstawiania.

Szczęśliwe programowanie!

Informacje o autorze

Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można go uzyskać pod adresem mitchell@4GuysFromRolla.com.

Specjalne podziękowania

Ta seria samouczków została omówiona przez wielu przydatnych recenzentów. Główni recenzenci dla tego samouczka to Hilton Giesenow i Teresa Murphy. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, napisz do mnie na adres mitchell@4GuysFromRolla.com.