Delen via


Batch verwijderen (C#)

door Scott Mitchell

PDF downloaden

Meer informatie over het verwijderen van meerdere databaserecords in één bewerking. In de gebruikersinterfacelaag bouwen we voort op een verbeterde GridView die in een eerdere zelfstudie is gemaakt. In de Data Access-laag verpakken we de meerdere verwijderingsbewerkingen binnen een transactie om ervoor te zorgen dat alle verwijderingen zijn geslaagd of dat alle verwijderingen worden teruggedraaid.

Introductie

In de voorgaande zelfstudie hebt u gezien hoe u een batchbewerkingsinterface maakt met behulp van een volledig bewerkbare GridView. In situaties waarin gebruikers vaak veel records tegelijk bewerken, vereist een batchbewerkingsinterface veel minder postbacks en toetsenbord-naar-muiscontextswitches, waardoor de efficiëntie van de eindgebruiker wordt verbeterd. Deze techniek is vergelijkbaar handig voor pagina's waar gebruikers veel records in één gebruik kunnen verwijderen.

Iedereen die een online-e-mailclient heeft gebruikt, is al bekend met een van de meest voorkomende interfaces voor het verwijderen van batches: een selectievakje in elke rij in een raster met een bijbehorende knop Alle ingeschakelde items verwijderen (zie afbeelding 1). Deze zelfstudie is vrij kort omdat we al het harde werk in vorige zelfstudies hebben gedaan bij het maken van zowel de webinterface als een methode voor het verwijderen van een reeks records als één atomische bewerking. In de zelfstudie Het toevoegen van een GridView-kolom met selectievakjes hebben we een GridView gemaakt met een kolom met selectievakjes en in de zelfstudie Databasemodificaties binnen een transactie verpakken hebben we een methode gemaakt in de BLL die een transactie zou gebruiken om een List<T> van ProductID waarden te verwijderen. In deze zelfstudie bouwen we voort op en voegen we onze eerdere ervaringen samen om een voorbeeld van het verwijderen van een werkende batch te maken.

Elke rij bevat een selectievakje

Afbeelding 1: Elke rij bevat een selectievakje (klik om de volledige afbeelding weer te geven)

Stap 1: Creëer de interface voor batchverwijdering

Omdat we de batch-interface al hebben gemaakt in de zelfstudie Een GridView-kolom met selectievakjes toevoegen, kunnen we deze gewoon naar BatchDelete.aspx kopiëren in plaats van het helemaal opnieuw te maken. Open eerst de BatchDelete.aspx pagina in de BatchData map en de CheckBoxField.aspx pagina in de EnhancedGridView map. Ga vanaf de CheckBoxField.aspx pagina naar de bronweergave en kopieer de markeringen tussen de <asp:Content> tags, zoals weergegeven in afbeelding 2.

De declaratieve markering van CheckBoxField.aspx naar het Klembord kopiëren

Afbeelding 2: Kopieer de declaratieve markeringen CheckBoxField.aspx naar het Klembord (klik om de afbeelding op volledige grootte weer te geven)

Ga vervolgens naar de bronweergave in BatchDelete.aspx en plak de inhoud van het klembord binnen de <asp:Content> tags. Kopieer en plak de code ook vanuit de code-behind-klasse in CheckBoxField.aspx.cs naar de code-behind-klasse in BatchDelete.aspx.cs (de DeleteSelectedProducts gebeurtenishandler van de knop Click, de ToggleCheckState methode en de Click gebeurtenishandlers voor de CheckAll en UncheckAll knoppen). Na het kopiëren van deze inhoud moet de code-behind-klasse van de BatchDelete.aspx pagina de volgende code bevatten:

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

Nadat u de declaratieve markeringen en broncode hebt gekopieerd, kunt u even testen door deze te bekijken BatchDelete.aspx via een browser. U zou een GridView moeten zien waarin de eerste tien producten worden weergegeven. Elke rij toont de naam, categorie en prijs van het product, samen met een selectievakje. Er moeten drie knoppen zijn: Alles controleren, Alles uitschakelen en Geselecteerde producten verwijderen. Als u op de knop Alles controleren klikt, worden alle selectievakjes geselecteerd, terwijl op Alles deselecteren klikken alle selectievakjes deselecteert. Als u op Geselecteerde producten verwijderen klikt, wordt een bericht weergegeven met de ProductID waarden van de geselecteerde producten, maar worden de producten niet daadwerkelijk verwijderd.

De interface van CheckBoxField.aspx is verplaatst naar BatchDeleting.aspx

Afbeelding 3: De interface van CheckBoxField.aspx is verplaatst naar BatchDeleting.aspx (Klik om de afbeelding op volledige grootte weer te geven)

Stap 2: de gecontroleerde producten verwijderen met behulp van transacties

Als de batchverwerkingsinterface is gekopieerd naar BatchDeleting.aspx, hoeft u alleen maar de code bij te werken, zodat de knop Geselecteerde producten verwijderen de gecontroleerde producten verwijdert met behulp van de DeleteProductsWithTransaction methode in de ProductsBLL klasse. Deze methode, toegevoegd aan de tutorial Databasewijzigingen binnen een transactie verpakken, accepteert als invoer een reeks List<T> van ProductID waarden en verwijdert elke bijbehorende ProductID binnen het bereik van een transactie.

De DeleteSelectedProducts gebeurtenis-handler van Click Knop gebruikt momenteel de volgende foreach lus om elke GridView-rij te doorlopen:

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

Voor elke rij wordt er programmatisch verwezen naar het ProductSelector Selectievakje webcontrole. Als deze optie is ingeschakeld, worden de rijen ProductID opgehaald uit de DataKeys verzameling en wordt de DeleteResults eigenschap Label s Text bijgewerkt met een bericht dat aangeeft dat de rij is geselecteerd voor verwijdering.

Met de bovenstaande code worden geen records verwijderd omdat de aanroep van de ProductsBLL methode klasse Delete wordt uitgecommentarieerd. Als deze verwijderlogica werd toegepast, zou de code de producten verwijderen, maar niet binnen een atomische bewerking. Als de eerste paar verwijderingen in de reeks zijn geslaagd, maar een latere verwijdering is mislukt (mogelijk vanwege een schending van een vreemde-sleutelbeperking), dan zou er een uitzondering optreden, maar de producten die al zijn verwijderd, blijven verwijderd.

Om atomiciteit te garanderen, moeten we in plaats daarvan de ProductsBLL klassemethode DeleteProductsWithTransaction gebruiken. Omdat deze methode een lijst ProductID met waarden accepteert, moeten we deze lijst eerst compileren vanuit het raster en deze vervolgens doorgeven als parameter. We maken eerst een instantie van een List<T> van het type int. Binnen de foreach lus moeten we de geselecteerde productenwaarden ProductID aan dit List<T>toevoegen. Na de lus moet deze List<T> worden doorgegeven aan de ProductsBLL klasse s DeleteProductsWithTransaction methode. Werk de eventhandler van de DeleteSelectedProducts knop Click bij met de volgende 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();
    }
}

De bijgewerkte code maakt een List<T> van type int (productIDsToDelete) en vult deze met de ProductID waarden om te verwijderen. Als er na de foreach lus ten minste één product is geselecteerd, wordt de ProductsBLL klassemethode DeleteProductsWithTransaction aangeroepen en doorgegeven aan deze lijst. Het DeleteResults label wordt ook weergegeven en de gegevens worden teruggezet naar de GridView (zodat de zojuist verwijderde records niet meer als rijen in het raster worden weergegeven).

In afbeelding 4 ziet u de GridView nadat een aantal rijen is geselecteerd voor verwijdering. In afbeelding 5 ziet u het scherm direct nadat op de knop Geselecteerde producten verwijderen is geklikt. Houd er rekening mee dat in afbeelding 5 de ProductID waarden van de verwijderde records worden weergegeven in het label onder de GridView en dat deze rijen zich niet meer in de GridView bevinden.

De geselecteerde producten worden verwijderd

Afbeelding 4: De geselecteerde producten worden verwijderd (klik hier om de volledige afbeelding weer te geven)

De product-id-waarden van verwijderde producten worden weergegeven onder de GridView

Afbeelding 5: De waarden van verwijderde producten ProductID worden weergegeven onder de GridView (klik hier om de volledige afbeelding weer te geven)

Opmerking

Als u de atomiciteit van de DeleteProductsWithTransaction methode wilt testen, voegt u handmatig een vermelding toe voor een product in de Order Details tabel en probeert u dat product te verwijderen (samen met anderen). U krijgt een schending van de buitenlandse sleutelbeperking bij het verwijderen van het product met een bijbehorende bestelling, maar let op hoe het terugdraaien van de verwijderingen van andere geselecteerde producten plaatsvindt.

Samenvatting

Het maken van een batch-verwijderinterface omvat het toevoegen van een GridView met een kolom met selectievakjes en een knopwebbesturingselement dat, wanneer erop wordt geklikt, alle geselecteerde rijen als één atomische bewerking verwijdert. In deze zelfstudie hebben we zo'n interface gebouwd door het werk uit twee eerdere zelfstudies samen te voegen: Toevoegen van een GridView-kolom met selectievakjes en Databasewijzigingen verpakken binnen een transactie. In de eerste zelfstudie hebben we een GridView gemaakt met een kolom met selectievakjes en in de tweede hebben we een methode geïmplementeerd in de BLL die, wanneer een List<T> van ProductID-waarden werd doorgegeven, deze allemaal binnen het bereik van een transactie verwijderde.

In de volgende zelfstudie maken we een interface voor het uitvoeren van batchinvoegingen.

Veel plezier met programmeren!

Over de auteur

Scott Mitchell, auteur van zeven ASP/ASP.NET-boeken en oprichter van 4GuysFromRolla.com, werkt sinds 1998 met Microsoft-webtechnologieën. Scott werkt als onafhankelijk consultant, trainer en schrijver. Zijn laatste boek is Sams Teach Yourself ASP.NET 2.0 in 24 uur. Hij kan worden bereikt op mitchell@4GuysFromRolla.com.

Speciale dank aan

Deze tutorialreeks is beoordeeld door veel behulpzame beoordelers. Hoofdrevisoren voor deze zelfstudie waren Hilton Giesenow en Teresa Murphy. Bent u geïnteresseerd in het bekijken van mijn aanstaande MSDN-artikelen? Zo ja, laat iets van je horen via mitchell@4GuysFromRolla.com.