2015-03-05 10 views
7

Ho letto un documento dal gruppo di pratiche Microsoft & (Data Access for Highly-Scalable Solutions: Using SQL, NoSQL, and Polyglot Persistence).L'utilizzo di TransactionScope nelle query Entity Framework è una buona idea?

Nel capitolo 3, nella sezione "Retrieving Data from the SQL Server Database", gli autori discutono sull'utilizzo di Entity Framework per caricare entità da un database. Ecco un po 'del loro codice di esempio:

using (var context = new PersonContext()) 
{ 
    Person person = null; 

    using (var transactionScope = this.GetTransactionScope()) 
    { 
     person = context.Persons 
      .Include(p => p.Addresses) 
      .Include(p => p.CreditCards) 
      .Include(p => p.EmailAddresses) 
      .Include(p => p.Password) 
      .SingleOrDefault(p => p.BusinessEntityId == personId); 

     transactionScope.Complete(); 
    } 

    // etc... 
} 

Nota l'uso di un ambito della transazione personalizzato tramite il metodo GetTransactionScope, implementato nella loro classe contesto di base in questo modo:

public abstract class BaseRepository 
{ 
    private static TransactionOptions transactionOptions = new TransactionOptions() 
    { 
     IsolationLevel = IsolationLevel.ReadCommitted 
    }; 

    protected virtual TransactionScope GetTransactionScope() 
    { 
     return new TransactionScope(TransactionScopeOption.Required, transactionOptions); 
    } 
} 

Working with Transactions (EF6 Onwards) su MSDN afferma:

In tutte le versioni di Entity Framework, ogni volta che si esegue SaveChanges() per inserire, aggiornare o eliminare sul database, il framework eseguirà il wrapping di tale operazione in una transazione [... ] il livello di isolamento della transazione è qualsiasi livello di isolamento che il provider di database considera la sua impostazione predefinita. Per impostazione predefinita, ad esempio, su SQL Server questo è READ COMMITTED. Entity Framework non esegue il wrapping delle query in una transazione. Questa funzionalità predefinita è adatta per molti utenti

L'enfasi è mia.

La mia domanda: è l'uso di un TransactionScope come mostrato sopra eccessivo, in particolare per i dati di legge, quando si utilizza Entity Framework?

(mi sono reso conto dopo la pubblicazione che la risposta a questa domanda potrebbe essere un po 'opinione basata, dispiace.)

+0

Con questo 'isolationLevel', questo codice è eccessivo se la transazione contiene solo operazioni di lettura. Ma se 'isolationLevel' è' ReadUncommited', questo codice ti consentirà di leggere la riga sporca (non ancora impegnata). –

+1

Si dovrebbe evitare l'ambito della transazione se non ha uno scopo aziendale. questo per evitare deadlock e problemi di prestazioni. – MichaelD

risposta

5

La domanda è un po 'aperta. Ma può rivelarsi utile per le persone che imparano a leggere le letture sporche. Isolamento ed EF. E avete letto EF Transaction Scope ef6 e abbiamo una domanda chiara.

In generale, direi che EF gestirà l'ambito. I principianti non considerano letture non vincolate ed è un buon valore predefinito per EF.

Potresti avere un motivo valido per voler controllare l'ambito. Oppure è necessario utilizzare una transazione esistente. Ma rimane per uso specialistico.

Quindi ora la vera domanda.
È buona norma includere tale programmazione difensiva attorno all'isolamento.

mio punto di vista:
Solo se doesnt rendere il codice più difficile da mantenere, e più difficile da riutilizzare.

Oracle e il server SQL hanno l'impostazione predefinita Lettura confermata. Mi aspetterei così su altri DB. Concluderei quindi, molto probabilmente una protezione non necessaria che aggiunge complessità.
Non lo aggiungerei al mio codice.

+0

EF non dice che ha un ambito di transazione predefinito al di fuori di SaveChanges, crea TransactionScope quando si crea il contesto? –

2

Dipende. Se si desidera eseguire letture sporche, letture serializzabili, ecc. Eccetto il livello di isolamento predefinito, è necessario avvolgere le query all'interno di un ambito di transazione.

1

Per mantenere l'integrità dei dati, a volte è utile utilizzare una transazione multi-statement definita in modo esplicito in modo che se una qualsiasi parte della transazione fallisce, viene eseguito il rollback. La decisione sull'opportunità o meno di utilizzare una transazione non dovrebbe essere presa alla leggera. Le transazioni esplicite, specialmente quelle distribuite, hanno un costo maggiore per le prestazioni e aprono il sistema fino ai deadlock e alla possibilità che una transazione possa essere lasciata aperta, bloccando la tabella interessata e bloccando tutte le altre transazioni. Inoltre, il codice è molto più difficile da sviluppare e mantenere.

Nella mia esperienza, ho scoperto che l'utilizzo di un ambito di transazione nel codice C# è più complicato rispetto all'utilizzo di una transazione esplicita in SQL. Pertanto, per le operazioni che potrebbero trarre vantaggio da una transazione, e in realtà qualsiasi query sufficientemente complessa, suggerirei di creare una stored procedure da chiamare dall'ORM.

1

Hai letto il seguente link? https://msdn.microsoft.com/en-us/library/vstudio/bb738523%28v=vs.100%29.aspx

Se si sceglie di usare il normale comportamento di SaveChanges senza di essa cominciano parte di un TransactionScope non sarebbe in grado di estendere la transazione al di là dei confini del database. L'utilizzo dell'ambito della transazione come nel riferimento sopra rende il messaggio in coda parte della transazione. Quindi se per qualche motivo l'invio del messaggio fallisce, anche la transazione fallisce.

Ovviamente si potrebbe considerare questo uno scenario più complesso. Nelle applicazioni semplici che non richiedono una logica così complessa, è probabilmente più sicuro usare la semplice saveChanges api.

Problemi correlati