Share via


Introduzione alla concorrenza dei dati in ADO.NET

Aggiornamento: novembre 2007

Quando più utenti tentano di modificare dei dati nello stesso momento, è necessario impostare dei controlli allo scopo di impedire che le modifiche apportate da un utente danneggino le modifiche apportate contemporaneamente da altri utenti. Il sistema di gestione di questo tipo di situazioni è detto controllo della concorrenza.

Tipi di controllo della concorrenza

Sono in genere disponibili tre metodi per la gestione della concorrenza in un database:

  • Controllo pessimistico della concorrenza: una riga non è disponibile per gli utenti dal momento in cui il record viene recuperato fino a quando non viene aggiornato nel database.

  • Controllo ottimistico della concorrenza: una riga non è disponibile per gli altri utenti solo durante l'effettivo aggiornamento dei dati. Viene esaminata la riga nel database per determinare se sono state apportate delle modifiche. Il tentativo di aggiornare un record che è già stato modificato determina una violazione di concorrenza.

  • "Last in wins" (vince l'ultimo aggiornamento): una riga non è disponibile per gli altri utenti solo durante l'effettivo aggiornamento dei dati. Tuttavia, non viene effettuato alcun confronto tra gli aggiornamenti e il record originale. Il record viene semplicemente memorizzato, sovrascrivendo potenzialmente le eventuali modifiche apportate da altri utenti a partire dall'ultima lettura dei record.

Concorrenza pessimistica

In genere, la concorrenza pessimistica viene utilizzata per due motivi. In primo luogo, in alcune situazioni è presente un'alta possibilità di conflitto per gli stessi record. I costi determinati dal posizionamento dei blocchi sui dati sono inferiori ai costi dell'annullamento delle modifiche quando si verificano dei conflitti di concorrenza.

La concorrenza pessimistica si rivela utile inoltre nelle situazioni in cui la modifica di un record durante l'esecuzione di una transazione può risultare dannosa. Un esempio è rappresentato da un'applicazione di inventario: si consideri il caso di un agente di un'azienda che consulta l'inventario per un potenziale cliente. In genere si blocca il record finché non viene generato un ordine, in seguito al quale gli articoli desiderati verranno contrassegnati con lo stato di ordinato e rimossi dall'inventario contenente gli articoli disponibili. Se non viene generato alcun ordine, il blocco verrà rilasciato in modo che gli altri utenti che controllano l'inventario possano ottenere un conteggio accurato degli articoli dell'inventario disponibili.

Tuttavia, il controllo pessimistico della concorrenza non è possibile in un'architettura disconnessa. Le connessioni sono aperte solo per un periodo di tempo sufficiente per la lettura o l'aggiornamento dei dati, per cui non è possibile conservare i blocchi per lungo tempo. Inoltre, un'applicazione che conservi i blocchi per lunghi periodi non è scalabile.

Concorrenza ottimistica

Nella concorrenza ottimistica i blocchi vengono impostati e mantenuti solo durante l'accesso al database. I blocchi impediscono ad altri utenti di tentare l'aggiornamento dei record nello stesso momento. I dati sono sempre disponibili tranne che nel momento esatto in cui avviene un aggiornamento. Per ulteriori informazioni, vedere Concorrenza ottimistica (ADO.NET).

Quando si tenta di effettuare un aggiornamento, la versione originale di una riga modificata viene confrontata con la riga esistente nel database. Se le due versioni sono diverse, l'aggiornamento non avrà esito positivo e sarà generato un errore di concorrenza. A questo punto spetta all'utente risolvere le differenze tra le due righe, utilizzando la logica di business creata.

Last in Wins (vince l'ultimo aggiornamento)

Con il sistema "last in wins" (vince l'ultimo aggiornamento), non viene svolto alcun controllo dei dati originali e l'aggiornamento viene semplicemente memorizzato nel database. Di conseguenza, può verificarsi la seguente situazione:

  • L'utente A recupera un record dal database.

  • L'utente B recupera lo stesso record dal database, lo modifica e memorizza il record aggiornato nel database.

  • L'utente A modifica il "vecchio" record e lo memorizza nel database.

Nello scenario sopra illustrato, le modifiche apportate dall'utente B non vengono mai viste dall'utente A. Assicurarsi che questa situazione sia accettabile se si intende utilizzare l'approccio "last in wins" per il controllo della concorrenza.

Controllo della concorrenza in ADO.NET e Visual Studio

In ADO.NET e Visual Studio viene utilizzata la concorrenza ottimistica, poiché l'architettura dei dati si basa su dati disconnessi. Di conseguenza, sarà necessario applicare una logica di business per risolvere i problemi di concorrenza ottimistica.

Se si sceglie di utilizzare la concorrenza ottimistica, saranno disponibili due metodi generali per determinare se sono state apportate delle modifiche: l'approccio relativo alla versione, vale a dire il controllo dei numeri di versione reali o degli indicatori reali di data e ora, e l'approccio costituito dal salvataggio di tutti i valori.

Controllo del numero di versione

Per controllare il numero di versione, è necessario che il record da aggiornare disponga di una colonna contenente un indicatore di data e ora o un numero di versione. Quando il record viene letto, nel client viene salvato l'indicatore di data e ora o un numero di versione. Questo valore viene quindi incluso nell'aggiornamento.

Un metodo per gestire la concorrenza consiste nell'effettuare l'aggiornamento solo se il valore riportato nella clausola WHERE corrisponde al valore presente nel record. La rappresentazione SQL di questo approccio è:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2 
WHERE DateTimeStamp = @origDateTimeStamp

In alternativa, è possibile effettuare il confronto utilizzando il numero di versione:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2 
WHERE RowVersion = @origRowVersionValue

Se gli indicatori di data e ora o i numeri di versione corrispondono, il record dell'archivio dati non è stato modificato e potrà essere aggiornato senza problemi con i nuovi valori dal dataset. Se invece non vi è corrispondenza, viene restituito un errore. È possibile scrivere il codice per implementare questa forma di controllo della concorrenza in Visual Studio. Sarà inoltre necessario scrivere il codice per rispondere a eventuali conflitti di aggiornamento. Per conservare la precisione dell'indicatore di data e ora o del numero di versione, è necessario impostare un trigger nella tabella, che ne effettui l'aggiornamento quando viene apportata una modifica a una riga.

Salvataggio di tutti i valori

Un'alternativa all'utilizzo di un indicatore di data e ora o di un numero di versione consiste nel recuperare delle copie di tutti i campi quando il record viene letto. Nell'oggetto DataSet di ADO.NET sono conservate due versioni di ciascun record modificato: una versione originale, quella inizialmente letta dall'origine dati, e una versione modificata, che rappresenta gli aggiornamenti dell'utente. Quando si tenta di memorizzare nuovamente il record nell'origine dati, i valori originali della riga di dati vengono confrontati con il record dell'origine dati. Se i valori corrispondono, significa che il record del database non è stato modificato dopo la lettura. In tal caso, i valori modificati del dataset vengono memorizzati correttamente nel database.

Ciascun comando dell'adattatore dati dispone di un insieme di parametri per ciascuno dei quattro comandi (DELETE, INSERT, SELECT e UPDATE). Ciascun comando dispone di parametri sia per i valori originali sia per i valori correnti o modificati.

Nota:

L'aggiunta di nuovi record, tramite il comando INSERT, richiede solamente i valori correnti, in quanto non esiste alcun record originale, mentre la rimozione dei record, tramite il comando DELETE, richiede solo i valori originali per individuare il record da eliminare.

Nel seguente esempio viene riportato il testo del comando del dataset tramite il quale avviene l'aggiornamento di una tipica tabella Customers. Il comando viene specificato per SQL dinamico e per la concorrenza ottimistica.

UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,
       ContactTitle = currContactTitle, Address = @currAddress, City = @currCity, 
       PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFax
WHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)
      AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL) 
      AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,
       PostalCode, Phone, Fax
FROM Customers WHERE (CustomerID = @currCustomerID)

Si tenga presente che i nove parametri dell'istruzione SET rappresentano i valori correnti che verranno memorizzati nel database, mentre i nove parametri dell'istruzione WHERE rappresentano i valori originali utilizzati per individuare il record originale.

I primi nove parametri dell'istruzione SET corrispondono ai primi nove parametri dell'insieme di parametri. La proprietà SourceVersion di questi parametri dovrà essere impostata su Current.

I successivi nove parametri dell'istruzione WHERE vengono utilizzati per la concorrenza ottimistica. Questi segnaposto corrisponderanno ai successivi nove parametri dell'insieme di parametri e la proprietà SourceVersion di ciascuno di questi parametri sarà impostata su Original.

L'istruzione SELECT viene utilizzata per aggiornare il dataset dopo l'aggiornamento. Viene generata quando si imposta l'opzione Aggiorna DataSet nella finestra di dialogo Opzioni avanzate generazione istruzioni SQL.

Nota:

Nell'istruzione SQL precedente vengono utilizzati parametri denominati, mentre nei comandi OleDbDataAdapter vengono utilizzati punti interrogativi (?) come segnaposto dei parametri.

In base all'impostazione predefinita, in Visual Studio questi parametri vengono creati automaticamente se si seleziona l'opzione Usa concorrenza ottimistica nella Configurazione guidata adattatore dati. Spetta all'utente aggiungere il codice per gestire gli errori in base alle esigenze aziendali. In ADO.NET è disponibile un oggetto DBConcurrencyException che restituisce la riga che viola le regole di concorrenza. Per ulteriori informazioni, vedere Procedura: gestire gli errori di concorrenza.

Vedere anche

Attività

Procedura: gestire gli errori di concorrenza

Concetti

Concorrenza ottimistica (ADO.NET)

Riferimenti

DBConcurrencyException