Gestione degli errori di commit delle transazioni

Nota

Solo EF6.1 E versioni successive : le funzionalità, le API e così via descritte in questa pagina sono state introdotte in Entity Framework 6.1. Se si usa una versione precedente, le informazioni qui riportate, o parte di esse, non sono applicabili.

Nell'ambito della versione 6.1 è stata introdotta una nuova funzionalità di resilienza della connessione per EF: la possibilità di rilevare e ripristinare automaticamente quando gli errori di connessione temporanei influiscono sull'acknowledgement dei commit delle transazioni. I dettagli completi dello scenario sono descritti meglio nel post di blog database SQL Connettività e problema di idempotenza. In sintesi, lo scenario è che quando viene generata un'eccezione durante un commit della transazione esistono due possibili cause:

  1. Il commit della transazione non è riuscito nel server
  2. Il commit della transazione è riuscito nel server, ma un problema di connettività ha impedito che la notifica di esito positivo raggiunga il client

Quando si verifica la prima situazione, l'applicazione o l'utente può ripetere l'operazione, ma quando si verifica la seconda situazione è consigliabile evitare nuovi tentativi e l'applicazione potrebbe essere ripristinata automaticamente. La sfida è che senza la possibilità di rilevare il motivo effettivo per cui è stata segnalata un'eccezione durante il commit, l'applicazione non può scegliere il corso di azione corretto. La nuova funzionalità di EF 6.1 consente a ENTITY Framework di eseguire il doppio controllo con il database se la transazione ha avuto esito positivo e intraprendere il corso corretto in modo trasparente.

Uso della funzionalità

Per abilitare la funzionalità necessaria, includere una chiamata a SetTransactionHandler nel costruttore di DbConfiguration. Se non si ha familiarità con DbConfiguration, vedere Configurazione basata su codice. Questa funzionalità può essere usata in combinazione con i tentativi automatici introdotti in EF6, che aiutano nella situazione in cui la transazione effettivamente non è riuscita a eseguire il commit sul server a causa di un errore temporaneo:

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.SqlServer;

public class MyConfiguration : DbConfiguration  
{
  public MyConfiguration()  
  {  
    SetTransactionHandler(SqlProviderServices.ProviderInvariantName, () => new CommitFailureHandler());  
    SetExecutionStrategy(SqlProviderServices.ProviderInvariantName, () => new SqlAzureExecutionStrategy());  
  }  
}

Modalità di rilevamento delle transazioni

Quando la funzionalità è abilitata, Ef aggiungerà automaticamente una nuova tabella al database denominato __Transactions. Una nuova riga viene inserita in questa tabella ogni volta che viene creata una transazione da Ef e tale riga viene verificata se si verifica un errore di transazione durante il commit.

Anche se EF eseguirà un'operazione ottimale per eliminare le righe dalla tabella quando non sono più necessarie, la tabella può aumentare se l'applicazione esce prematuramente e per questo motivo potrebbe essere necessario ripulire manualmente la tabella in alcuni casi.

Come gestire gli errori di commit con le versioni precedenti

Prima di EF 6.1 non esisteva alcun meccanismo per gestire gli errori di commit nel prodotto EF. Esistono diversi modi per gestire questa situazione che possono essere applicati alle versioni precedenti di EF6:

  • Opzione 1 - Non eseguire alcuna operazione

    La probabilità di un errore di connessione durante il commit della transazione è bassa, quindi può essere accettabile che l'applicazione non riesca se questa condizione si verifica effettivamente.

  • Opzione 2- Usare il database per reimpostare lo stato

    1. Eliminare il DbContext corrente
    2. Creare un nuovo DbContext e ripristinare lo stato dell'applicazione dal database
    3. Informare l'utente che l'ultima operazione potrebbe non essere stata completata correttamente
  • Opzione 3 - Tenere traccia manuale della transazione

    1. Aggiungere una tabella non rilevata al database usato per tenere traccia dello stato delle transazioni.
    2. Inserire una riga nella tabella all'inizio di ogni transazione.
    3. Se la connessione non riesce durante il commit, verificare la presenza della riga corrispondente nel database.
      • Se la riga è presente, continuare normalmente, perché è stato eseguito correttamente il commit della transazione
      • Se la riga è assente, usare una strategia di esecuzione per ritentare l'operazione corrente.
    4. Se il commit ha esito positivo, eliminare la riga corrispondente per evitare la crescita della tabella.

Questo post di blog contiene codice di esempio per eseguire questa operazione in SQL Azure.