Freigeben über


Löschen in Batches (C#)

von Scott Mitchell

PDF herunterladen

Erfahren Sie, wie Sie mehrere Datenbankdatensätze in einem einzelnen Vorgang löschen. In der Benutzeroberflächenebene bauen wir auf einer erweiterten GridView auf, die in einem früheren Tutorial erstellt wurde. In der Datenzugriffsebene werden die mehreren Löschvorgänge innerhalb einer Transaktion umgebrochen, um sicherzustellen, dass alle Löschungen erfolgreich sind oder dass ein Rollback für alle Löschungen ausgeführt wird.

Einführung

Im vorherigen Tutorial wurde das Erstellen einer Batchbearbeitungsschnittstelle mithilfe eines vollständig bearbeitbaren GridView-Steuerelements erläutert. In Situationen, in denen Benutzer häufig viele Datensätze gleichzeitig bearbeiten, erfordert eine Batchbearbeitungsoberfläche weitaus weniger Postbacks und Kontextwechsel zwischen Tastatur und Maus, wodurch die Effizienz des Endbenutzers verbessert wird. Dieses Verfahren ist ähnlich nützlich für Seiten, auf denen Benutzer häufig viele Datensätze auf einmal löschen.

Jeder, der einen Online-E-Mail-Client verwendet hat, ist bereits mit einer der häufigsten Batchlöschschnittstellen vertraut: ein Kontrollkästchen in jeder Zeile in einem Raster mit einer entsprechenden Schaltfläche Alle überprüften Elemente löschen (siehe Abbildung 1). Dieses Tutorial ist ziemlich kurz, da wir bereits die gesamte harte Arbeit in den vorherigen Tutorials beim Erstellen der webbasierten Schnittstelle und einer Methode zum Löschen einer Reihe von Datensätzen als einzelner atomarer Vorgang ausgeführt haben. Im Tutorial Hinzufügen einer GridView-Spalte von Kontrollkästchen haben wir eine GridView mit einer Spalte von Kontrollkästchen erstellt, und im Tutorial Wrapping Database Modifications in a Transaction haben wir eine Methode in der BLL erstellt, die eine Transaktion zum Löschen von ProductID Werten List<T> verwendet. In diesem Tutorial bauen wir auf unseren bisherigen Erfahrungen auf und führen sie zusammen, um ein beispiel für das Löschen eines funktionierenden Batchs zu erstellen.

Jede Zeile enthält ein Kontrollkästchen

Abbildung 1: Jede Zeile enthält ein Kontrollkästchen (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Schritt 1: Erstellen der Batchlöschschnittstelle

Da wir die Batchlöschschnittstelle bereits im Tutorial Hinzufügen einer GridView-Spalte von Kontrollkästchen erstellt haben , können wir sie BatchDelete.aspx einfach kopieren, anstatt sie von Grund auf neu zu erstellen. Öffnen Sie zunächst die BatchDelete.aspx Seite im BatchData Ordner und die CheckBoxField.aspx Seite im EnhancedGridView Ordner. Wechseln Sie auf der CheckBoxField.aspx Seite zur Quellansicht, und kopieren Sie das Markup zwischen den <asp:Content> Tags, wie in Abbildung 2 dargestellt.

Kopieren des deklarativen Markups von CheckBoxField.aspx in die Zwischenablage

Abbildung 2: Kopieren des deklarativen Markups von CheckBoxField.aspx in die Zwischenablage (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Wechseln Sie als Nächstes zur Quellansicht, BatchDelete.aspx und fügen Sie den Inhalt der Zwischenablage in die <asp:Content> Tags ein. Kopieren Sie auch den Code aus der CodeBehind-Klasse in CheckBoxField.aspx.cs , und fügen Sie ihn innerhalb der CodeBehind-Klasse in BatchDelete.aspx.cs ein (den DeleteSelectedProducts Ereignishandler von Button, Click die ToggleCheckState -Methode und die Click Ereignishandler für die CheckAll Schaltflächen und UncheckAll ). Nach dem Kopieren dieses Inhalts sollte die BatchDelete.aspx CodeBehind-Klasse der Seite den folgenden Code enthalten:

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);
    }
}

Nehmen Sie sich nach dem Kopieren des deklarativen Markups und des Quellcodes einen Moment Zeit, um es zu testen BatchDelete.aspx , indem Sie es über einen Browser anzeigen. Es sollte ein GridView-Objekt angezeigt werden, in dem die ersten zehn Produkte in einer GridView aufgeführt sind, wobei jede Zeile den Namen, die Kategorie und den Preis des Produkts zusammen mit einem Kontrollkästchen auflistet. Es sollten drei Schaltflächen vorhanden sein: Alle überprüfen, Alle deaktivieren und Ausgewählte Produkte löschen. Durch Klicken auf die Schaltfläche Alle überprüfen werden alle Kontrollkästchen aktiviert, während alle Kontrollkästchen deaktiviert werden. Wenn Sie auf Ausgewählte Produkte löschen klicken, wird eine Meldung angezeigt, in der die ProductID Werte der ausgewählten Produkte aufgelistet sind, die Produkte jedoch nicht gelöscht werden.

Die Schnittstelle aus CheckBoxField.aspx wurde in BatchDeleting.aspx verschoben.

Abbildung 3: Die Schnittstelle von CheckBoxField.aspx wurde zu verschoben (Klicken Sie hier, umBatchDeleting.aspx das Bild in voller Größe anzuzeigen)

Schritt 2: Löschen der überprüften Produkte mithilfe von Transaktionen

Nachdem die Batchlöschschnittstelle erfolgreich in BatchDeleting.aspxkopiert wurde, bleibt nur noch der Code zu aktualisieren, sodass die Schaltfläche Ausgewählte Produkte löschen die überprüften Produkte mithilfe der DeleteProductsWithTransaction -Methode in der ProductsBLL -Klasse löscht. Diese Methode, die im Tutorial Wrapping Database Modifications in a Transaction hinzugefügt wurde, akzeptiert als Eingabe eine List<T> von ProductID Werten und löscht alle innerhalb des Bereichs einer Transaktion entsprechenden ProductID .

Der DeleteSelectedProducts Button-Ereignishandler Click verwendet derzeit die folgende foreach Schleife, um jede GridView-Zeile zu durchlaufen:

// 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);
        //............................................
    }
}

Für jede Zeile wird programmgesteuert auf das ProductSelector CheckBox-Websteuerelement verwiesen. Wenn dies aktiviert ist, werden die Zeilen ProductID aus der DataKeys Auflistung abgerufen, und die DeleteResults Label s-Eigenschaft Text wird aktualisiert, sodass sie eine Meldung enthält, die angibt, dass die Zeile zum Löschen ausgewählt wurde.

Der obige Code löscht tatsächlich keine Datensätze, da der Aufruf der ProductsBLL Klasse s-Methode Delete auskommentiert ist. Würde diese Löschlogik angewendet, würde der Code die Produkte löschen, aber nicht innerhalb eines atomischen Vorgangs. Das heißt, wenn die ersten Löschvorgänge in der Sequenz erfolgreich waren, aber ein späterer Fehler aufgetreten ist (möglicherweise aufgrund eines Verstoßes gegen eine Fremdschlüsseleinschränkung), würde eine Ausnahme ausgelöst, aber die bereits gelöschten Produkte würden gelöscht.

Um die Atomarität sicherzustellen, müssen wir stattdessen die -Methode der ProductsBLL Klasse s DeleteProductsWithTransaction verwenden. Da diese Methode eine Liste von ProductID Werten akzeptiert, müssen wir diese Liste zuerst aus dem Raster kompilieren und dann als Parameter übergeben. Zuerst erstellen wir eine instance vom List<T> Typ int. Innerhalb der foreach Schleife müssen wir diesem List<T>die werte für ausgewählte Produkte ProductID hinzufügen. Nach der Schleife muss diese List<T> an die s-Methode der ProductsBLL Klasse DeleteProductsWithTransaction übergeben werden. Aktualisieren Sie den DeleteSelectedProducts Button s-Ereignishandler Click mit dem folgenden Code:

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();
    }
}

Der aktualisierte Code erstellt einen List<T> vom Typ int (productIDsToDelete) und füllt es mit den ProductID zu löschenden Werten auf. Wenn nach der foreach Schleife mindestens ein Produkt ausgewählt ist, wird die ProductsBLL Klasse s-Methode DeleteProductsWithTransaction aufgerufen und diese Liste übergeben. Die DeleteResults Bezeichnung wird auch angezeigt, und die Daten werden an gridView zurückgegeben (sodass die neu gelöschten Datensätze nicht mehr als Zeilen im Raster angezeigt werden).

Abbildung 4 zeigt die GridView, nachdem eine Reihe von Zeilen zum Löschen ausgewählt wurde. Abbildung 5 zeigt den Bildschirm unmittelbar nach dem Klicken auf die Schaltfläche Ausgewählte Produkte löschen. Beachten Sie, dass in Abbildung 5 die ProductID Werte der gelöschten Datensätze in der Bezeichnung unterhalb von GridView angezeigt werden und diese Zeilen nicht mehr in der GridView enthalten sind.

Die ausgewählten Produkte werden gelöscht.

Abbildung 4: Die ausgewählten Produkte werden gelöscht (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Die ProductID-Werte für gelöschte Produkte werden unter der Rasteransicht aufgeführt.

Abbildung 5: Die Werte für gelöschte Produkte ProductID sind unter der GridView aufgeführt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Hinweis

Um die Atomarität der DeleteProductsWithTransaction Methode zu testen, fügen Sie manuell einen Eintrag für ein Produkt in der Order Details Tabelle hinzu, und versuchen Sie dann, dieses Produkt (zusammen mit anderen) zu löschen. Wenn Sie versuchen, das Produkt mit einer zugeordneten Bestellung zu löschen, erhalten Sie einen Verstoß gegen die Fremdschlüsseleinschränkung. Beachten Sie jedoch, wie für die löschungen der anderen ausgewählten Produkte ein Rollback ausgeführt wird.

Zusammenfassung

Zum Erstellen einer Batchlöschschnittstelle wird eine GridView mit einer Spalte mit Kontrollkästchen und ein Button Web-Steuerelement hinzugefügt, das beim Klicken alle ausgewählten Zeilen als einzelnen atomischen Vorgang löscht. In diesem Tutorial haben wir eine solche Schnittstelle erstellt, indem wir die Arbeit in zwei vorherigen Tutorials zusammenfügen: Hinzufügen einer GridView-Spalte von Kontrollkästchen und Umschließen von Datenbankänderungen innerhalb einer Transaktion. Im ersten Tutorial haben wir ein GridView-Objekt mit einer Spalte mit Kontrollkästchen erstellt, und in letzterem haben wir eine Methode in der BLL implementiert, die bei Übergabe eines List<T> von ProductID Werten alle innerhalb des Bereichs einer Transaktion gelöscht hat.

Im nächsten Tutorial erstellen wir eine Schnittstelle zum Ausführen von Batcheinfügungen.

Viel Spaß beim Programmieren!

Zum Autor

Scott Mitchell, Autor von sieben ASP/ASP.NET-Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Er kann unter mitchell@4GuysFromRolla.comoder über seinen Blog erreicht werden, der unter http://ScottOnWriting.NETzu finden ist.

Besonderer Dank an

Diese Tutorialreihe wurde von vielen hilfreichen Prüfern überprüft. Leitende Gutachter für dieses Tutorial waren Hilton Giesenow und Teresa Murphy. Möchten Sie meine bevorstehenden MSDN-Artikel lesen? Wenn dies der Fall ist, legen Sie eine Zeile unter abmitchell@4GuysFromRolla.com.