Implementazione della concorrenza ottimistica con SqlDataSource (C#)
In questa esercitazione vengono esaminati i concetti fondamentali del controllo della concorrenza ottimistica e quindi viene illustrato come implementarlo usando il controllo SqlDataSource.
Introduzione
Nell'esercitazione precedente è stato illustrato come aggiungere funzionalità di inserimento, aggiornamento ed eliminazione al controllo SqlDataSource. In breve, per fornire queste funzionalità è necessario specificare l'istruzione , UPDATE
o DELETE
SQL corrispondente INSERT
nelle proprietà , UpdateCommand
o del controllo , InsertCommand
o DeleteCommand
, insieme ai parametri appropriati nelle InsertParameters
raccolte , UpdateParameters
e DeleteParameters
. Anche se queste proprietà e raccolte possono essere specificate manualmente, il pulsante Avanzate della Procedura guidata Configura origine dati offre una casella di controllo Genera INSERT
istruzioni , UPDATE
e DELETE
che creerà automaticamente queste istruzioni in base all'istruzione SELECT
.
Insieme alla casella di controllo Genera INSERT
istruzioni , UPDATE
e DELETE
, la finestra di dialogo Opzioni avanzate di generazione SQL include un'opzione Usa concorrenza ottimistica (vedere la figura 1). Se selezionata, le WHERE
clausole nella generazione UPDATE
automatica e DELETE
le istruzioni vengono modificate per eseguire l'aggiornamento o l'eliminazione solo se i dati del database sottostanti non sono stati modificati dall'ultimo caricamento dei dati nella griglia.
Figura 1: È possibile aggiungere il supporto della concorrenza ottimistica dalla finestra di dialogo Opzioni avanzate di generazione SQL
Nell'esercitazione Implementazione della concorrenza ottimistica sono stati esaminati i concetti fondamentali del controllo della concorrenza ottimistica e come aggiungerlo a ObjectDataSource. In questa esercitazione verranno ritoccati gli elementi essenziali del controllo della concorrenza ottimistica e quindi si esaminerà come implementarlo usando SqlDataSource.
Riepilogo della concorrenza ottimistica
Per le applicazioni Web che consentono a più utenti simultanei di modificare o eliminare gli stessi dati, esiste la possibilità che un utente sovrascriva accidentalmente altre modifiche. Nell'esercitazione Implementazione della concorrenza ottimistica ho fornito l'esempio seguente:
Si supponga che due utenti, Jisun e Sam, visitassero entrambe una pagina in un'applicazione che consentiva ai visitatori di aggiornare ed eliminare i prodotti tramite un controllo GridView. Entrambi fare clic sul pulsante Modifica per Chai nello stesso momento. Jisun modifica il nome del prodotto in Chai Tea e fa clic sul pulsante Aggiorna. Il risultato netto è un'istruzione UPDATE
inviata al database, che imposta tutti i campi aggiornabili del prodotto (anche se Jisun ha aggiornato un solo campo, ProductName
). A questo punto, il database ha i valori Chai Tea, la categoria Beverages, il fornitore Esotico Liquids e così via per questo particolare prodotto. Tuttavia, la schermata GridView in Sam mostra ancora il nome del prodotto nella riga GridView modificabile come Chai. Dopo il commit delle modifiche di Jisun, Sam aggiorna la categoria a Condimenti e fa clic su Aggiorna. Viene restituita un'istruzione UPDATE
inviata al database che imposta il nome del prodotto su Chai, sull'ID CategoryID
categoria Condiments corrispondente e così via. Le modifiche di Jisun al nome del prodotto sono state sovrascritte.
La figura 2 illustra questa interazione.
Figura 2: Quando due utenti aggiornano simultaneamente un record è possibile che un utente modichi per sovrascrivere l'altro (fare clic per visualizzare l'immagine a dimensione intera)
Per impedire lo svolgimento di questo scenario, è necessario implementare una forma di controllo della concorrenza . La concorrenza ottimistica che si concentra su questa esercitazione si basa sul presupposto che, sebbene ci siano conflitti di concorrenza ogni ora e poi, la maggior parte del tempo tali conflitti non si verificheranno. Pertanto, se si verifica un conflitto, il controllo della concorrenza ottimistica informa semplicemente l'utente che le modifiche non possono essere salvate perché un altro utente ha modificato gli stessi dati.
Nota
Per le applicazioni in cui si presuppone che ci saranno molti conflitti di concorrenza o se tali conflitti non sono tollerabili, è possibile usare invece un controllo di concorrenza pessimistico. Fare riferimento all'esercitazione Implementazione della concorrenza ottimistica per una discussione più approfondita sul controllo della concorrenza pessimistica.
Il controllo della concorrenza ottimistica funziona assicurandosi che il record da aggiornare o eliminare abbia gli stessi valori di quando è stato avviato il processo di aggiornamento o eliminazione. Ad esempio, quando si fa clic sul pulsante Modifica in un controllo GridView modificabile, i valori dei record vengono letti dal database e visualizzati in Caselle di testo e in altri controlli Web. Questi valori originali vengono salvati da GridView. Successivamente, dopo che l'utente apporta le modifiche e fa clic sul pulsante Aggiorna, l'istruzione UPDATE
utilizzata deve tenere conto dei valori originali più i nuovi valori e aggiornare il record del database sottostante solo se i valori originali che l'utente ha iniziato a modificare sono identici ai valori ancora presenti nel database. La figura 3 illustra questa sequenza di eventi.
Figura 3: Per eseguire l'aggiornamento o l'eliminazione, i valori originali devono essere uguali ai valori del database corrente (fare clic per visualizzare l'immagine a dimensione intera)
Esistono vari approcci all'implementazione della concorrenza ottimistica (vedere La logica di aggiornamento ottimistico della concorrenza ottimistica di Peter A. Kuberneberg per una breve panoramica delle opzioni). La tecnica usata da SqlDataSource (nonché dai set di dati tipizzati di ADO.NET usati nel livello di accesso ai dati) aumenta la WHERE
clausola per includere un confronto di tutti i valori originali. L'istruzione seguente UPDATE
, ad esempio, aggiorna il nome e il prezzo di un prodotto solo se i valori del database correnti sono uguali ai valori recuperati originariamente durante l'aggiornamento del record in GridView. I @ProductName
parametri e @UnitPrice
contengono i nuovi valori immessi dall'utente, mentre @original_ProductName
e @original_UnitPrice
contengono i valori originariamente caricati in GridView quando si fa clic sul pulsante Modifica:
UPDATE Products SET
ProductName = @ProductName,
UnitPrice = @UnitPrice
WHERE
ProductID = @original_ProductID AND
ProductName = @original_ProductName AND
UnitPrice = @original_UnitPrice
Come si vedrà in questa esercitazione, l'abilitazione del controllo della concorrenza ottimistica con SqlDataSource è semplice come selezionare una casella di controllo.
Passaggio 1: Creazione di un oggetto SqlDataSource che supporta la concorrenza ottimistica
Per iniziare, aprire la OptimisticConcurrency.aspx
pagina dalla SqlDataSource
cartella . Trascinare un controllo SqlDataSource dalla casella degli strumenti nella Designer, impostare la relativa ID
proprietà su ProductsDataSourceWithOptimisticConcurrency
. Fare quindi clic sul collegamento Configura origine dati dallo smart tag del controllo. Nella prima schermata della procedura guidata scegliere di usare NORTHWINDConnectionString
e fare clic su Avanti.
Figura 4: Scegliere di usare (fare clic per visualizzare l'immagineNORTHWINDConnectionString
a dimensione intera)
Per questo esempio si aggiungerà un controllo GridView che consente agli utenti di modificare la Products
tabella. Di conseguenza, nella schermata Configura istruzione seleziona, scegliere la Products
tabella dall'elenco a discesa e selezionare le ProductID
colonne , ProductName
, UnitPrice
e Discontinued
, come illustrato nella figura 5.
Figura 5: Dalla Products
tabella, restituire le ProductID
colonne , ProductName
, UnitPrice
e Discontinued
(fare clic per visualizzare l'immagine a dimensione intera)
Dopo aver selezionato le colonne, fare clic sul pulsante Avanzate per visualizzare la finestra di dialogo Opzioni avanzate di generazione SQL. Selezionare le caselle di controllo Genera INSERT
istruzioni , UPDATE
e DELETE
Usa concorrenza ottimistica e fare clic su OK (fare riferimento alla figura 1 per uno screenshot). Completare la procedura guidata facendo clic su Avanti, quindi su Fine.
Dopo aver completato la procedura guidata Configura origine dati, esaminare le proprietà e risultanti DeleteCommand
e le DeleteParameters
raccolte e UpdateParameters
.UpdateCommand
Il modo più semplice per eseguire questa operazione consiste nel fare clic sulla scheda Origine nell'angolo inferiore sinistro per visualizzare la sintassi dichiarativa della pagina. Qui troverai un UpdateCommand
valore di:
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
Con sette parametri nella UpdateParameters
raccolta:
<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ...>
<DeleteParameters>
...
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="ProductName" Type="String" />
<asp:Parameter Name="UnitPrice" Type="Decimal" />
<asp:Parameter Name="Discontinued" Type="Boolean" />
<asp:Parameter Name="original_ProductID" Type="Int32" />
<asp:Parameter Name="original_ProductName" Type="String" />
<asp:Parameter Name="original_UnitPrice" Type="Decimal" />
<asp:Parameter Name="original_Discontinued" Type="Boolean" />
</UpdateParameters>
...
</asp:SqlDataSource>
Analogamente, la proprietà e DeleteParameters
la DeleteCommand
raccolta dovrebbero essere simili alle seguenti:
DELETE FROM [Products]
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ...>
<DeleteParameters>
<asp:Parameter Name="original_ProductID" Type="Int32" />
<asp:Parameter Name="original_ProductName" Type="String" />
<asp:Parameter Name="original_UnitPrice" Type="Decimal" />
<asp:Parameter Name="original_Discontinued" Type="Boolean" />
</DeleteParameters>
<UpdateParameters>
...
</UpdateParameters>
...
</asp:SqlDataSource>
Oltre ad aumentare le WHERE
clausole delle UpdateCommand
proprietà e DeleteCommand
(e aggiungere i parametri aggiuntivi alle rispettive raccolte di parametri), selezionando l'opzione Usa concorrenza ottimistica si modificano due altre proprietà:
- Modifica la
ConflictDetection
proprietà daOverwriteChanges
(impostazione predefinita) aCompareAllValues
- Modifica la
OldValuesParameterFormatString
proprietà da {0} (impostazione predefinita) a original_{0} .
Quando il controllo Web dei dati richiama il metodo o Delete()
sqlDataSourceUpdate()
, passa i valori originali. Se la proprietà sqlDataSource s ConflictDetection
è impostata su CompareAllValues
, questi valori originali vengono aggiunti al comando. La OldValuesParameterFormatString
proprietà fornisce il modello di denominazione usato per questi parametri di valore originale. La procedura guidata Configura origine dati usa original_{0} e assegna un nome a ogni parametro originale nelle DeleteCommand
UpdateCommand
proprietà e nelle raccolte e UpdateParameters
DeleteParameters
di conseguenza.
Nota
Poiché non si usano le funzionalità di inserimento del controllo SqlDataSource, è possibile rimuovere la proprietà e la InsertCommand
relativa InsertParameters
raccolta.
Gestione corretta deiNULL
valori
Sfortunatamente, le istruzioni e DELETE
aumentate UPDATE
generate automaticamente dalla procedura guidata Configura origine dati quando si usa la concorrenza ottimistica non funzionano con i record che contengono NULL
valori. Per vedere perché, prendere in considerazione sqlDataSource s UpdateCommand
:
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
La UnitPrice
colonna nella Products
tabella può avere NULL
valori. Se un determinato record ha un NULL
valore per UnitPrice
, la parte [UnitPrice] = @original_UnitPrice
della WHERE
clausola restituirà sempre False perché NULL = NULL
restituisce sempre False. Pertanto, i record che contengono NULL
valori non possono essere modificati o eliminati, perché le UPDATE
clausole e DELETE
delle istruzioni WHERE
non restituiscono righe da aggiornare o eliminare.
Nota
Questo bug è stato segnalato per la prima volta a Microsoft nel mese di giugno 2004 in SqlDataSource genera istruzioni SQL non corrette e viene segnalato come corretto nella versione successiva di ASP.NET.
Per risolvere questo problema, è necessario aggiornare manualmente le WHERE
clausole in entrambe le UpdateCommand
proprietà e DeleteCommand
per tutte le colonne che possono avere NULL
valori. In generale, passare [ColumnName] = @original_ColumnName
a:
(
([ColumnName] IS NULL AND @original_ColumnName IS NULL)
OR
([ColumnName] = @original_ColumnName)
)
Questa modifica può essere eseguita direttamente tramite il markup dichiarativo, tramite le opzioni UpdateQuery o DeleteQuery dal Finestra Proprietà oppure tramite le schede UPDATE e DELETE nell'opzione Specificare un'istruzione SQL personalizzata o una stored procedure nella procedura guidata Configura origine dati. Anche in questo caso, questa modifica deve essere apportata per ogni colonna nella UpdateCommand
clausola e DeleteCommand
s WHERE
che può contenere NULL
valori.
Applicando questo valore all'esempio vengono restituiti i valori e DeleteCommand
modificati UpdateCommand
seguenti:
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
DELETE FROM [Products]
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
Passaggio 2: Aggiunta di un controllo GridView con opzioni di modifica ed eliminazione
Con SqlDataSource configurato per supportare la concorrenza ottimistica, tutto ciò che rimane consiste nell'aggiungere un controllo Web dati alla pagina che usa questo controllo di concorrenza. Per questa esercitazione, è possibile aggiungere un controllo GridView che fornisce funzionalità di modifica ed eliminazione. A tale scopo, trascinare un controllo GridView dalla casella degli strumenti nella Designer e impostarlo ID
su Products
. Dallo smart tag gridView, associarlo al ProductsDataSourceWithOptimisticConcurrency
controllo SqlDataSource aggiunto al passaggio 1. Infine, selezionare le opzioni Abilita modifica e Abilita eliminazione dallo smart tag.
Figura 6: Associare GridView a SqlDataSource e abilitare la modifica e l'eliminazione (fare clic per visualizzare l'immagine a dimensione intera)
Dopo aver aggiunto GridView, configurarne l'aspetto rimuovendo BoundField ProductID
, modificando la ProductName
proprietà BoundField in HeaderText
Product e aggiornando BoundField UnitPrice
in modo che la relativa HeaderText
proprietà sia semplicemente Price. Idealmente, si migliora l'interfaccia di modifica per includere un RequiredFieldValidator per il ProductName
valore e un CompareValidator per il UnitPrice
valore (per assicurarsi che sia un valore numerico formattato correttamente). Vedere l'esercitazione Personalizzazione dell'interfaccia di modifica dei dati per un'analisi più approfondita della personalizzazione dell'interfaccia di modifica di GridView.
Nota
Lo stato di visualizzazione di GridView deve essere abilitato perché i valori originali passati da GridView a SqlDataSource vengono archiviati nello stato di visualizzazione.
Dopo aver apportato queste modifiche a GridView, il markup dichiarativo GridView e SqlDataSource dovrebbe essere simile al seguente:
<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ConflictDetection="CompareAllValues"
ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
DeleteCommand=
"DELETE FROM [Products]
WHERE [ProductID] = @original_ProductID
AND [ProductName] = @original_ProductName
AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice))
AND [Discontinued] = @original_Discontinued"
OldValuesParameterFormatString=
"original_{0}"
SelectCommand=
"SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued]
FROM [Products]"
UpdateCommand=
"UPDATE [Products]
SET [ProductName] = @ProductName, [UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE [ProductID] = @original_ProductID
AND [ProductName] = @original_ProductName
AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice))
AND [Discontinued] = @original_Discontinued">
<DeleteParameters>
<asp:Parameter Name="original_ProductID" Type="Int32" />
<asp:Parameter Name="original_ProductName" Type="String" />
<asp:Parameter Name="original_UnitPrice" Type="Decimal" />
<asp:Parameter Name="original_Discontinued" Type="Boolean" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="ProductName" Type="String" />
<asp:Parameter Name="UnitPrice" Type="Decimal" />
<asp:Parameter Name="Discontinued" Type="Boolean" />
<asp:Parameter Name="original_ProductID" Type="Int32" />
<asp:Parameter Name="original_ProductName" Type="String" />
<asp:Parameter Name="original_UnitPrice" Type="Decimal" />
<asp:Parameter Name="original_Discontinued" Type="Boolean" />
</UpdateParameters>
</asp:SqlDataSource>
<asp:GridView ID="Products" runat="server"
AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="ProductsDataSourceWithOptimisticConcurrency">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="Price"
SortExpression="UnitPrice" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Columns>
</asp:GridView>
Per visualizzare il controllo della concorrenza ottimistica in azione, aprire due finestre del browser e caricare la OptimisticConcurrency.aspx
pagina in entrambi. Fare clic sui pulsanti Modifica per il primo prodotto in entrambi i browser. In un browser modificare il nome del prodotto e fare clic su Aggiorna. Il browser eseguirà il postback e GridView tornerà alla modalità di pre-modifica, mostrando il nuovo nome del prodotto per il record appena modificato.
Nella seconda finestra del browser modificare il prezzo (ma lasciare il nome del prodotto come valore originale) e fare clic su Aggiorna. Al postback, la griglia torna alla modalità di pre-modifica, ma la modifica al prezzo non viene registrata. Il secondo browser mostra lo stesso valore del primo nome del nuovo prodotto con il prezzo precedente. Le modifiche apportate nella seconda finestra del browser sono andate perse. Inoltre, le modifiche sono state perse in modo piuttosto silenzioso, poiché non vi sono state eccezioni o messaggi che indicano che si è appena verificata una violazione della concorrenza.
Figura 7: Le modifiche nella seconda finestra del browser sono state perse automaticamente (fare clic per visualizzare l'immagine a dimensione intera)
Il motivo per cui non è stato eseguito il commit delle modifiche apportate al secondo browser è stato dovuto al fatto che la clausola dell'istruzione UPDATE
ha WHERE
filtrato tutti i record e pertanto non ha effetto sulle righe. Esaminiamo di nuovo l'istruzione UPDATE
:
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR
([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
Quando la seconda finestra del browser aggiorna il record, il nome del prodotto originale specificato nella WHERE
clausola non corrisponde al nome del prodotto esistente (poiché è stato modificato dal primo browser). Pertanto, l'istruzione [ProductName] = @original_ProductName
restituisce False e non UPDATE
influisce sui record.
Nota
L'eliminazione funziona nello stesso modo. Con due finestre del browser aperte, iniziare modificando un determinato prodotto con uno e quindi salvandone le modifiche. Dopo aver salvato le modifiche in un browser, fare clic sul pulsante Elimina per lo stesso prodotto nell'altro. Poiché i valori originali non corrispondono nella clausola dell'istruzione DELETE
, WHERE
l'eliminazione non riesce automaticamente.
Dal punto di vista dell'utente finale nella seconda finestra del browser, dopo aver fatto clic sul pulsante Aggiorna, la griglia torna alla modalità di pre-modifica, ma le modifiche sono andate perse. Tuttavia, non c'è alcun feedback visivo che le modifiche non sono state attaccate. Idealmente, se le modifiche apportate da un utente vengono perse a una violazione della concorrenza, è possibile inviare una notifica e, forse, mantenere la griglia in modalità di modifica. Esaminiamo come eseguire questa operazione.
Passaggio 3: Determinare quando si è verificata una violazione della concorrenza
Poiché una violazione della concorrenza rifiuta le modifiche apportate, sarebbe bello avvisare l'utente quando si è verificata una violazione della concorrenza. Per avvisare l'utente, è possibile aggiungere un controllo Web Etichetta nella parte superiore della pagina denominata ConcurrencyViolationMessage
la cui Text
proprietà visualizza il messaggio seguente: Si è tentato di aggiornare o eliminare un record che è stato aggiornato contemporaneamente da un altro utente. Esaminare le modifiche dell'altro utente e quindi ripetere l'aggiornamento o l'eliminazione. Impostare la proprietà S del CssClass
controllo Label su Warning, ovvero una classe CSS definita in Styles.css
che visualizza il testo in un tipo di carattere rosso, corsivo, grassetto e grande. Impostare infine le proprietà Label s Visible
e EnableViewState
su false
. In questo modo l'etichetta verrà nascosta, ad eccezione dei postback in cui la proprietà viene impostata Visible
in modo esplicito su true
.
Figura 8: Aggiungere un controllo Etichetta alla pagina per visualizzare l'avviso (fare clic per visualizzare l'immagine a dimensione intera)
Quando si esegue un aggiornamento o un'eliminazione, i gestori eventi e RowDeleted
di RowUpdated
GridView vengono attivati dopo che il controllo origine dati ha eseguito l'aggiornamento o l'eliminazione richiesti. È possibile determinare il numero di righe interessate dall'operazione da questi gestori eventi. Se sono state interessate zero righe, si vuole visualizzare l'etichetta ConcurrencyViolationMessage
.
Creare un gestore eventi per gli RowUpdated
eventi e RowDeleted
e aggiungere il codice seguente:
protected void Products_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
if (e.AffectedRows == 0)
{
ConcurrencyViolationMessage.Visible = true;
e.KeepInEditMode = true;
// Rebind the data to the GridView to show the latest changes
Products.DataBind();
}
}
protected void Products_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
if (e.AffectedRows == 0)
ConcurrencyViolationMessage.Visible = true;
}
In entrambi i gestori eventi viene controllata la e.AffectedRows
proprietà e, se è uguale a 0, impostare la ConcurrencyViolationMessage
proprietà Label s Visible
su true
. RowUpdated
Nel gestore eventi viene inoltre indicato a GridView di rimanere in modalità di modifica impostando la KeepInEditMode
proprietà su true. In questo modo, è necessario riassociare i dati alla griglia in modo che gli altri dati dell'utente vengano caricati nell'interfaccia di modifica. Questa operazione viene eseguita chiamando il metodo gridView s DataBind()
.
Come illustrato nella figura 9, con questi due gestori eventi, viene visualizzato un messaggio molto evidente ogni volta che si verifica una violazione della concorrenza.
Figura 9: Un messaggio viene visualizzato in faccia a una violazione di concorrenza (fare clic per visualizzare l'immagine a dimensione intera)
Riepilogo
Quando si crea un'applicazione Web in cui più utenti simultanei possono modificare gli stessi dati, è importante considerare le opzioni di controllo della concorrenza. Per impostazione predefinita, i controlli Web ASP.NET dati e i controlli origine dati non usano alcun controllo di concorrenza. Come illustrato in questa esercitazione, l'implementazione del controllo della concorrenza ottimistica con SqlDataSource è relativamente rapida e semplice. SqlDataSource gestisce la maggior parte delle attività per l'aggiunta di clausole aumentate WHERE
alle istruzioni e DELETE
generate UPDATE
automaticamente, ma nella gestione NULL
delle colonne dei valori sono presenti alcune sottigliezze, come illustrato nella sezione Gestione corretta dei NULL
valori.
Questa esercitazione conclude l'esame di SqlDataSource. Le esercitazioni rimanenti torneranno a usare i dati usando ObjectDataSource e l'architettura a livelli.
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.