NHibernate con TransactionScope

Qualcuno può darmi una rapida panoramica sull’utilizzo di TransactionScope con NHibernate? Devo fare qualcosa di speciale con la sessione / IEnlistmentNotification / etc. per farlo funzionare? Ci sono delle insidie ​​di cui dovrei preoccuparmi? Ad esempio, posso sostituire tutte le mie transazioni di sospensione:

var transaction = session.BeginTransaction(); try { // code transaction.Commit(); } catch (Exception) { transaction.Rollback(); } 

con questo?:

 using (var scope = new TransactionScope()) { // code scope.Complete(); } 

Ho utilizzato nHibernate 2.1 per un po ‘, e dopo alcuni problemi di produzione e diverse varianti, abbiamo optato per il seguente metodo, come per evitare le connessioni che perdono con NHibernate e TransactionScope :

  using (var scope = new TransactionScope(TransactionScopeOption.Required)) { using (var session = sessionFactory.OpenSession()) using (var transaction = session.BeginTransaction()) { // do what you need to do with the session transaction.Commit(); } scope.Complete(); } 

Poiché stiamo utilizzando MSMQ e WCF, abbiamo dovuto utilizzare la transazione ambientale.

Abbiamo scoperto che non usare session.BeginTransaction () ha causato una perdita di connessione. Abbiamo anche scoperto che riutilizzare una sessione dopo aver eseguito una transazione ha causato una condizione di competizione (nHibernate non è thread-safe e DTSC Commits / Rollbacks si verificano su un thread in background).

Ho provato questo usando vari venditori e funziona. Se non si dispone di “scope.Complete ()”, la transazione verrà ripristinata. Potrebbe essere necessario che MSDTC esegua le macchine interessate se esiste più di una risorsa duratura. In tal caso, MSDTC rileverà automaticamente le transazioni ADO.NET e gestirà il tutto.

Quanto sopra funziona OK a condizione che si stia utilizzando un provider di connessioni che supporta l’utilizzo di un gestore transazioni leggero come SQL Server 2005/2008.

Se si utilizza SQL Server 7/2000, tutte le transazioni diventeranno transazioni distribuite anche se si colpisce solo un database / risorsa. Questo probabilmente non è ciò che si vorrebbe nella maggior parte dei casi e sarà costoso per quanto riguarda le prestazioni.

Quindi verifica se la combinazione di provider di connessione e server di database è adatta per l’uso con TransactionScope.

Credo che tu possa sostituire le transazioni di NHibernate con questo a condizione di rispettare alcuni vincoli, come alcuni hanno già detto:

  • Utilizzare una versione di NHibernate ragionevolmente recente ( > = 3.1 ).
  • Il fornitore di dati ADO.NET sottostante deve supportare TransactionScope (ok per SQL-Server, Oracle> = 10 con ODP.NET).
  • Crea la tua sessione di NH all’interno di TransactionScope per assicurarti che venga arruolato.
  • Maneggiare il lavaggio NHibernate manualmente. Vedi anche qui e qui .
  • Preparati per le transazioni distribuite. Se si creano più sessioni in un ambito, la transazione locale iniziale potrebbe essere promossa a una transazione distribuita. Ho visto questo accadere anche con le stesse stringhe di connessione su un DB Oracle 11.2 usando ODAC 11.2.0.3.20. Su SQL Server 2008 R2 non ha promosso. (A proposito, si può vedere questo osservando Transaction.Current.TransactionInformation.DistributedIdentifier che è nullo per le transazioni locali.) Mentre le transazioni distribuite hanno alcuni vantaggi, sono più costose ed è un po ‘più difficile impostarle. (Vedi qui come fare questo per Oracle). Per essere sicuro che la promozione non avvenga mai in Oracle, imposta ” Transazione promozionale = locale” nella stringa di connessione. Questo crea un’eccezione se qualche codice cerca di farlo.

Spero che sia tutto 😉

PS: ho aggiunto i dettagli Oracle perché erano il mio interesse e altri potrebbero trarne beneficio.

Inoltre, se si utilizza TransactionScope, eseguire l’aggiornamento a NHibernate 2.1. È solo con 2.1 che NH ha ottenuto una buona integrazione con TransactionScope.

Secondo Fabio Maulo nei commenti relativi a NH-2107 :

Puoi utilizzare TransactionScope e dovresti continuare a utilizzare anche la transazione di NH. Dove hai letto che l’uso di TransactionScope significa evitare l’uso della transazione di NH?

Avrei pensato che l’uso esplicito delle transazioni di NHibernate non fosse necessario, ma a parte questo è la migliore pratica