Salvataggio delle modifiche e gestione della concorrenza (Entity Framework)

Per impostazione predefinita, Entity Framework implementa un modello di concorrenza ottimistica. Questo significa che non vengono mantenuti blocchi sui dati nell'origine dati tra il momento in cui viene eseguita la query sui dati e l'aggiornamento dei dati. Le modifiche agli oggetti vengono salvate da Entity Framework nel database senza verificare la concorrenza. Per le entità che potrebbero presentare un elevato livello di concorrenza, è consigliabile che l'entità definisca una proprietà al livello concettuale con un attributo ConcurrencyMode="fixed", come illustrato nell'esempio seguente:

<Property Name="Status" Type="Byte" Nullable="false" ConcurrencyMode="Fixed" />

Quando viene utilizzato questo attributo, Entity Framework verifica le modifiche nel database prima di salvarle. Qualsiasi modifica in conflitto provoca un evento OptimisticConcurrencyException. Per ulteriori informazioni, vedere Procedura: gestire la concorrenza dei dati nel contesto dell'oggetto (Entity Framework). Può verificarsi un evento OptimisticConcurrencyException anche quando si definisce un modello Entity Data Model che utilizza stored procedure per gli aggiornamenti nell'origine dati. In questo caso, l'eccezione viene generata quando la stored procedure utilizzata per eseguire gli aggiornamenti indica che sono state aggiornate zero righe.

Quando si eseguono aggiornamenti negli scenari con concorrenza elevata, è consigliabile chiamare Refresh frequentemente. Quando si chiama Refresh, RefreshMode determina la modalità di propagazione delle modifiche. L'opzione StoreWins consente di fare in modo che Entity Framework sovrascriva tutti i dati nella cache degli oggetti con i valori corrispondenti del database. Viceversa, l'opzione ClientWins sostituisce i valori originali nella cache con i valori più recenti dell'origine dati. In questo modo, tutti i dati modificati nella cache degli oggetti possono essere salvati correttamente nell'origine dati, eliminando i conflitti tra le modifiche apportate ai dati nella cache e le modifiche apportate agli stessi dati nell'origine dati.

Chiamare il metodo Refresh dopo avere chiamato il metodo SaveChanges se gli aggiornamenti all'origine dati possono modificare i dati appartenenti ad altri oggetti del contesto dell'oggetto. Quando, ad esempio, viene aggiunto un nuovo oggetto SalesOrderDetail nel modello Sales di AdventureWorks, tramite i trigger viene aggiornata la colonna SubTotal per riflettere il subtotale con il nuovo elemento. In questo caso, chiamare il metodo Refresh e passare l'oggetto SalesOrderHeader per l'ordine. Questo garantisce che i valori generati tramite trigger vengono inviati di nuovo all'oggetto SalesOrderHeader nel contesto dell'oggetto.

Entity Framework consente di rilevare le modifiche apportate agli oggetti nella cache. Quando si chiama il metodo SaveChanges, Entity Framework tenta di unire le modifiche nuovamente nell'origine dati. SaveChanges può avere esito negativo e generare un evento OptimisticConcurrencyException quando le modifiche ai dati nella cache degli oggetti sono in conflitto con le modifiche apportate nell'origine dati dopo che gli oggetti sono stati aggiunti o aggiornati nella cache. In questo caso, viene eseguito il rollback dell'intera transazione. Quando si verifica un evento OptimisticConcurrencyException, è necessario gestirlo chiamando Refresh e specificando se il conflitto deve essere risolto mantenendo i dati nei dati dell'oggetto (ClientWins) o aggiornando la cache degli oggetti con i dati dell'origine dati (StoreWins), come nell'esempio seguente:

Try
    ' Try to save changes, which may cause a conflict. 
    Dim num As Integer = context.SaveChanges()
    Console.WriteLine("No conflicts. " & num.ToString() & " updates saved.")
Catch generatedExceptionName As OptimisticConcurrencyException
    ' Resolve the concurrency conflict by refreshing the 
    ' object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders)

    ' Save changes. 
    context.SaveChanges()
    Console.WriteLine("OptimisticConcurrencyException handled and changes saved")
End Try
try
{
    // Try to save changes, which may cause a conflict.
    int num = context.SaveChanges();
    Console.WriteLine("No conflicts. " +
        num.ToString() + " updates saved.");
}
catch (OptimisticConcurrencyException)
{
    // Resolve the concurrency conflict by refreshing the 
    // object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders);

    // Save changes.
    context.SaveChanges();
    Console.WriteLine("OptimisticConcurrencyException "
    + "handled and changes saved");
}

SaveChanges può comportare la generazione di un evento UpdateException quando un oggetto aggiunto a ObjectContext non può essere creato correttamente nell'origine dati. Questo può verificarsi se esiste già una riga con la chiave esterna specificata dalla relazione. In questo caso, non è possibile utilizzare Refresh per aggiornare l'oggetto aggiunto nel contesto dell'oggetto. Ricaricare invece l'oggetto con un valore di OverwriteChanges per MergeOption.

Per ulteriori informazioni sulla gestione del contesto dell'oggetto, vedere Procedura: gestire la concorrenza dei dati nel contesto dell'oggetto (Entity Framework).

È possibile scegliere di utilizzare le transazioni come alternativa alla concorrenza ottimistica. Per ulteriori informazioni, vedere Gestione di connessioni e transazioni (Entity Framework).

In questa sezione

Procedura: gestire la concorrenza dei dati nel contesto dell'oggetto (Entity Framework)

Vedere anche

Concetti

Utilizzo di oggetti (Entity Framework)
Creazione, aggiunta, modifica ed eliminazione di oggetti (Entity Framework)