Salvataggio delle modifiche e gestione della concorrenza (Entity Framework)

Entity Framework implementa un modello di concorrenza ottimistica. Questo significa che non vengono mantenuti blocchi sui dati nell'origine dati. Per impostazione predefinita, tuttavia, le modifiche agli oggetti vengono salvate da Object Services nel database senza verificare la concorrenza. Per le proprietà che potrebbero presentare un elevato livello di concorrenza, è consigliabile definire la proprietà dell'entità 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, tramite Object Services vengono controllate 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. Per ulteriori informazioni, vedere Supporto delle stored procedure (Entity Framework).

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 Object Services 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.

Object Services consente di rilevare le modifiche apportate agli oggetti nella cache. Quando viene chiamato il metodo SaveChanges, in Object Services viene eseguito un tentativo di unire di nuovo le modifiche 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 ex 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).

In Object Services vengono inoltre rispettate le transazioni definite utilizzando lo spazio dei nomi System.Transactions. Per ulteriori informazioni, vedere Gestione di transazioni in Object Services (Entity Framework).

Vedere anche

Concetti

Aggiunta, modifica ed eliminazione di oggetti (Entity Framework)

Altre risorse

Utilizzo di oggetti (Entity Framework)