Eliminazione batch (C#)

di Scott Mitchell

Scarica il PDF

Informazioni su come eliminare più record di database in una singola operazione. Nel livello dell'interfaccia utente si basa su un controllo GridView migliorato creato in un'esercitazione precedente. Nel livello di accesso ai dati vengono eseguite il wrapping delle più operazioni di eliminazione all'interno di una transazione per assicurarsi che tutte le eliminazioni abbiano esito positivo o venga eseguito il rollback di tutte le eliminazioni.

Introduzione

L'esercitazione precedente ha illustrato come creare un'interfaccia di modifica batch usando un controllo GridView completamente modificabile. Nelle situazioni in cui gli utenti modificano in genere molti record contemporaneamente, un'interfaccia di modifica batch richiederà un minor numero di postback e commutatori di contesto da tastiera a mouse, migliorando così l'efficienza dell'utente finale. Questa tecnica è analogamente utile per le pagine in cui è comune per gli utenti eliminare molti record in un'unica operazione.

Chiunque abbia usato un client di posta elettronica online ha già familiarità con una delle interfacce di eliminazione batch più comuni: una casella di controllo in ogni riga di una griglia con un pulsante Elimina tutti gli elementi selezionati corrispondente (vedere la figura 1). Questa esercitazione è piuttosto breve perché è già stato eseguito tutto il duro lavoro nelle esercitazioni precedenti per creare sia l'interfaccia basata sul Web che un metodo per eliminare una serie di record come singola operazione atomica. Nell'esercitazione Aggiunta di una colonna GridView delle caselle di controllo è stata creata un controllo GridView con una colonna di caselle di controllo e nell'esercitazione Wrapping delle modifiche del database in una transazione è stato creato un metodo nel BLL che userebbe una transazione per eliminare un List<T> di ProductID valori. In questa esercitazione verranno create e unite le esperienze precedenti per creare un esempio di eliminazione batch funzionante.

Ogni riga include una casella di controllo

Figura 1: Ogni riga include una casella di controllo (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 1: Creazione dell'interfaccia di eliminazione batch

Poiché l'interfaccia di eliminazione batch è già stata creata nell'esercitazione Aggiunta di una colonna GridView delle caselle di controllo , è sufficiente copiarla BatchDelete.aspx in anziché crearla da zero. Per iniziare, aprire la BatchDelete.aspx pagina nella BatchData cartella e nella CheckBoxField.aspx pagina nella EnhancedGridView cartella . CheckBoxField.aspx Dalla pagina passare alla visualizzazione Origine e copiare il markup tra i <asp:Content> tag, come illustrato nella figura 2.

Copiare il markup dichiarativo di CheckBoxField.aspx negli Appunti

Figura 2: Copiare il markup dichiarativo di CheckBoxField.aspx negli Appunti (fare clic per visualizzare l'immagine a dimensione intera)

Passare quindi alla visualizzazione Origine in BatchDelete.aspx e incollare il contenuto degli Appunti all'interno dei <asp:Content> tag. Copiare e incollare anche il codice dall'interno della classe code-behind in all'interno CheckBoxField.aspx.cs della classe code-behind in BatchDelete.aspx.cs (gestore DeleteSelectedProducts eventi Button s Click , il ToggleCheckState metodo e i Click gestori eventi per i CheckAll pulsanti e UncheckAll ). Dopo aver copiato su questo contenuto, la BatchDelete.aspx classe code-behind della pagina deve contenere il codice seguente:

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

Dopo aver copiato il markup dichiarativo e il codice sorgente, eseguire un test BatchDelete.aspx visualizzandolo tramite un browser. Verrà visualizzato un controllo GridView che elenca i primi dieci prodotti in un controllo GridView con ogni riga che elenca il nome, la categoria e il prezzo del prodotto insieme a una casella di controllo. Dovrebbero essere presenti tre pulsanti: Controlla tutto, Deseleziona tutto e Elimina prodotti selezionati. Facendo clic sul pulsante Controlla tutto, vengono selezionate tutte le caselle di controllo, mentre deseleziona tutte le caselle di controllo. Facendo clic su Elimina prodotti selezionati viene visualizzato un messaggio che elenca i ProductID valori dei prodotti selezionati, ma non elimina effettivamente i prodotti.

L'interfaccia di CheckBoxField.aspx è stata spostata in BatchDeleting.aspx

Figura 3: L'interfaccia da CheckBoxField.aspx è stata spostata in BatchDeleting.aspx (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 2: Eliminazione dei prodotti controllati tramite transazioni

Con l'interfaccia di eliminazione batch copiata BatchDeleting.aspxcorrettamente in , tutto ciò che rimane consiste nell'aggiornare il codice in modo che il pulsante Elimina prodotti selezionati elimini i prodotti selezionati usando il DeleteProductsWithTransaction metodo nella ProductsBLL classe . Questo metodo, aggiunto nell'esercitazione Wrapping delle modifiche del database all'interno di una transazione , accetta come input un List<T> di ProductID valori ed elimina ogni corrispondente ProductID nell'ambito di una transazione.

Il DeleteSelectedProducts gestore eventi button usa Click attualmente il ciclo seguente foreach per scorrere ogni riga gridView:

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

Per ogni riga, viene fatto riferimento al ProductSelector controllo Web CheckBox a livello di codice. Se è selezionata, la riga viene ProductID recuperata dall'insieme DataKeys e la DeleteResults proprietà Label s Text viene aggiornata per includere un messaggio che indica che la riga è stata selezionata per l'eliminazione.

Il codice precedente non elimina effettivamente alcun record perché la chiamata al ProductsBLL metodo della Delete classe viene impostata come commento. Se si applicasse questa logica di eliminazione, il codice eliminerebbe i prodotti ma non all'interno di un'operazione atomica. Ovvero, se le prime eliminazioni nella sequenza hanno avuto esito positivo, ma una successiva operazione non è riuscita (forse a causa di una violazione di un vincolo di chiave esterna), viene generata un'eccezione, ma tali prodotti già eliminati rimarranno eliminati.

Per garantire l'atomicità, è necessario usare invece il ProductsBLL metodo della classe .DeleteProductsWithTransaction Poiché questo metodo accetta un elenco di ProductID valori, è necessario prima compilare questo elenco dalla griglia e quindi passarlo come parametro. Per prima cosa si crea un'istanza di di List<T> tipo int. All'interno del foreach ciclo è necessario aggiungere i valori dei prodotti ProductID selezionati a questo List<T>. Dopo che il ciclo List<T> deve essere passato al ProductsBLL metodo della DeleteProductsWithTransaction classe . Aggiornare il DeleteSelectedProducts gestore eventi button con Click il codice seguente:

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

Il codice aggiornato crea un List<T> oggetto di tipo int (productIDsToDelete) e lo popola con i ProductID valori da eliminare. Dopo il foreach ciclo, se è selezionato almeno un prodotto, il ProductsBLL metodo della DeleteProductsWithTransaction classe viene chiamato e passato questo elenco. L'etichetta DeleteResults viene inoltre visualizzata e i dati vengono rimbalzati in GridView (in modo che i record appena eliminati non vengano più visualizzati come righe nella griglia).

La figura 4 mostra GridView dopo aver selezionato un numero di righe per l'eliminazione. Nella figura 5 viene visualizzata la schermata immediatamente dopo che è stato fatto clic sul pulsante Elimina prodotti selezionati. Si noti che nella figura 5 i ProductID valori dei record eliminati vengono visualizzati nell'etichetta sotto GridView e tali righe non sono più presenti in GridView.

I prodotti selezionati verranno eliminati

Figura 4: I prodotti selezionati verranno eliminati (fare clic per visualizzare l'immagine a dimensione intera)

I valori ProductID prodotti eliminati sono elencati sotto GridView

Figura 5: I valori dei prodotti ProductID eliminati sono elencati sotto GridView (fare clic per visualizzare l'immagine a dimensione intera)

Nota

Per testare l'atomicità DeleteProductsWithTransaction del metodo, aggiungere manualmente una voce per un prodotto nella Order Details tabella e quindi tentare di eliminare tale prodotto (insieme ad altri). Si riceverà una violazione del vincolo di chiave esterna quando si tenta di eliminare il prodotto con un ordine associato, ma si noti come viene eseguito il rollback delle altre eliminazioni di prodotti selezionati.

Riepilogo

La creazione di un'interfaccia di eliminazione batch comporta l'aggiunta di un controllo GridView con una colonna di caselle di controllo e un controllo Web Button che, quando si fa clic, eliminerà tutte le righe selezionate come singola operazione atomica. In questa esercitazione è stata creata un'interfaccia di questo tipo raggruppando le operazioni eseguite in due esercitazioni precedenti, Aggiunta di una colonna GridView di caselle di controllo e wrapping delle modifiche del database all'interno di una transazione. Nella prima esercitazione è stato creato un controllo GridView con una colonna di caselle di controllo e in quest'ultimo è stato implementato un metodo nel BLL che, quando viene passato un List<T> di ProductID valori, li ha eliminati tutti nell'ambito di una transazione.

Nell'esercitazione successiva verrà creata un'interfaccia per l'esecuzione di inserimenti batch.

Buon programmatori!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, lavora con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto all'indirizzo mitchell@4GuysFromRolla.com. o tramite il suo blog, disponibile all'indirizzo http://ScottOnWriting.NET.

Grazie speciale a

Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali di questa esercitazione sono stati Hilton Giesenow e Teresa Murphy. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciami una riga in mitchell@4GuysFromRolla.com.