Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Informazioni su come eliminare più record di database in una singola operazione. Nel livello dell'interfaccia utente costruiamo su un controllo GridView avanzato, creato in un'esercitazione precedente. Nel livello di accesso ai dati, incapsuliamo più operazioni di eliminazione all'interno di una transazione per assicurare che tutte le eliminazioni vadano a buon fine o che vengano ripristinate 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 è relativamente breve perché abbiamo già svolto tutto il lavoro difficile nelle esercitazioni precedenti, creando sia l'interfaccia basata su web che un metodo per cancellare una serie di record come singola operazione atomica.
Nell'esercitazione Aggiunta di una colonna GridView di caselle di controllo abbiamo creato un controllo GridView con una colonna di caselle di controllo e nell'esercitazione Wrapping delle modifiche del database in una transazione abbiamo creato un metodo nel BLL che usa una transazione per eliminare un List<T> di ProductID valori. In questa esercitazione ci baseremo e uniremo le esperienze precedenti per creare un esempio funzionante di eliminazione batch.
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é nell'esercitazione Aggiunta di una colonna di caselle di controllo a GridView è già stata creata l'interfaccia di eliminazione batch, è sufficiente copiarla in BatchDelete.aspx 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. Copia e incolla anche il codice dalla classe code-behind in CheckBoxField.aspx.vb alla classe code-behind in BatchDelete.aspx.vb (l'evento gestore di DeleteSelectedProducts per il pulsante Click, il metodo ToggleCheckState e gli event handlers per i pulsanti Click e CheckAll). Dopo aver copiato questo contenuto, la BatchDelete.aspx classe code-behind della pagina deve contenere il codice seguente:
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
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, con ogni riga che mostra il nome, la categoria e il prezzo del prodotto, insieme a una casella di controllo. Dovrebbero essere presenti tre pulsanti: Controlla tutto, Deseleziona tutto ed Elimina prodotti selezionati. Facendo clic sul pulsante Seleziona tutto, vengono selezionate tutte le caselle di controllo, mentre Deseleziona tutto 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 correttamente in BatchDeleting.aspx, 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 nel tutorial Involucro delle modifiche al database all'interno di una transazione, accetta come input un List(Of T) valori ProductID ed elimina ogni corrispondente ProductID nell'ambito di una transazione.
Il DeleteSelectedProducts gestore eventi del pulsante Click attualmente utilizza il seguente ciclo For Each per iterare attraverso ogni riga GridView:
' 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
Per ogni riga, viene fatto riferimento al ProductSelector controllo Web CheckBox a livello di codice. Se è selezionato, le righe ProductID vengono recuperate dall'insieme DataKeys e le proprietà di Label DeleteResults vengono aggiornate per includere un messaggio che indica che le righe sono state selezionate per l'eliminazione.
Il codice sopra non elimina effettivamente alcun record perché la chiamata al metodo della classe ProductsBLL è commentata con il simbolo Delete. Se si applicasse questa logica di eliminazione, il codice eliminerebbe i prodotti ma non in 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 metodo ProductsBLL della classe DeleteProductsWithTransaction. Poiché questo metodo accetta un elenco di ProductID valori, è necessario prima compilare questo elenco dalla griglia e quindi passarlo come parametro. Prima di tutto viene creata un'istanza di List(Of T) di tipo Integer. All'interno del For Each ciclo è necessario aggiungere i valori dei prodotti ProductID selezionati a questo List(Of T). Dopo il ciclo, questo List(Of T) deve essere passato al metodo ProductsBLL della classe DeleteProductsWithTransaction. Aggiornare il gestore eventi del pulsante DeleteSelectedProductsClick con il codice seguente:
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
Il codice aggiornato crea un List(Of T) oggetto di tipo Integer (productIDsToDelete) e lo popola con i ProductID valori da eliminare. Dopo il For Each ciclo, se è selezionato almeno un prodotto, viene chiamato il metodo della classe ProductsBLL e passato questo elenco DeleteProductsWithTransaction. Viene inoltre visualizzata l'etichetta DeleteResults e i dati vengono riascolti a GridView , in modo che i record appena eliminati non vengano più visualizzati come righe nella griglia.
La figura 4 mostra GridView dopo che è stata selezionata una serie di righe per l'eliminazione. Nella figura 5 viene visualizzata la schermata immediatamente dopo aver 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)
Annotazioni
Per testare l'atomicità del DeleteProductsWithTransaction metodo, aggiungere manualmente una voce per un prodotto nella Order Details tabella e quindi tentare di eliminare tale prodotto (insieme ad altri). Quando si tenta di eliminare il prodotto con un ordine associato, si riceverà una violazione del vincolo di chiave esterna, ma si noti come viene eseguito il rollback delle altre eliminazioni di prodotti selezionati.
Riassunto
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 combinando il lavoro svolto in due esercitazioni precedenti, l'aggiunta di una colonna di caselle di controllo nel GridView e l'incapsulamento delle modifiche al database all'interno di una transazione. Nella prima esercitazione è stato creato un controllo GridView con una colonna di caselle di controllo e nella seconda è stato implementato un metodo nel BLL che, una volta passato un List(Of T) contenente valori ProductID, li eliminava tutti nel contesto 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, ha lavorato 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 a mitchell@4GuysFromRolla.com.
Grazie speciale a
Questa serie di esercitazioni è stata esaminata da molti revisori competenti. I revisori principali per questa esercitazione sono stati Hilton Giesenow e Teresa Murphy. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, mandami un messaggio a mitchell@4GuysFromRolla.com.