Eliminazione batch (C#)
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.
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.
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.
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.aspx
correttamente 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.
Figura 4: I prodotti selezionati verranno eliminati (fare clic per visualizzare l'immagine a dimensione intera)
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.