2010-09-22 8 views
5

Il seguente frammento di codice funziona correttamente con SQL Server 2008 (SP1) ma con Oracle 11g la chiamata a session.BeginTransaction() genera un'eccezione con il messaggio "La connessione è già parte di un locale o di un transazione distribuita '(traccia dello stack mostrata sotto). Utilizzando "" NHibernate.Driver.OracleDataClientDriver ".Problema di NHibernate TransactionScope con Oracle 11g

Qualcun altro ha incontrato questo?

using (var scope = new TransactionScope()) 
{ 
    using (var session = sessionFactory.OpenSession()) 
    using (var transaction = session.BeginTransaction()) 
    { 
     // do what you need to do with the session 
     transaction.Commit(); 
    } 
    scope.Complete(); 
} 
 
    Exception at: at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel) 
      at NHibernate.Transaction.AdoTransaction.Begin() 
      at NHibernate.AdoNet.ConnectionManager.BeginTransaction() 
      at NHibernate.Impl.SessionImpl.BeginTransaction() 
      at MetraTech.BusinessEntity.DataAccess.Persistence.StandardRepository.SaveInstances(List`1& dataObjects) in S:\MetraTech\BusinessEntity\DataAccess\Persistence\StandardRepository.cs:line 3103 

     Inner error message was: Connection is already part of a local or a distributed transaction 
     Inner exception at: at Oracle.DataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel) 
      at Oracle.DataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel) 
      at System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction() 
      at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel) 

risposta

0

Una domanda, perché stai facendo il session.BeginTransaction interna - dal 2.1 GA NHibernate iscriverà automaticamente in contesti TransactionScope quindi non c'è alcun motivo per fare più il proprio.

+3

potrebbe essere quello di ottenere l'autoflush NHibernate per funzionare correttamente – Konstantin

7

Il problema con l'utilizzo solo ambito della transazione è descritto qui: NHibernate FlushMode Auto Not Flushing Before Find

Sembra NHibernate (v3.1 con Oracle 11g dialetto e db w/opd.net v2.112.1.2) richiede che sia proprie transazioni per evitare il problema di svuotamento, ma non sono stato in grado di far funzionare l'ambito della transazione con le transazioni Nibernate.

io non riesco a farlo funzionare :( questo potrebbe essere un difetto in NHibernate o odp.net, non è sicuro ...

trovato qui lo stesso problema: NHibernate 3.0: TransactionScope and Auto-Flushing

FISSO : trovata una soluzione! inserendo "enlist = dynamic;" nella mia stringa di connessione Oracle, il problema è stato risolto. Sono stato in grado di utilizzare sia la transazione nhibernate (per risolvere il problema di flush) sia l'ambito della transazione in questo modo:

 ISessionFactory sessionFactory = CreateSessionFactory(); 

     using (TransactionScope ts = new TransactionScope()) 
     { 
      using (ISession session = sessionFactory.OpenSession()) 
      using (ITransaction tx = session.BeginTransaction()) 
      { 
       //do stuff here 

       tx.Commit(); 

      } 
      ts.Complete(); 
     } 

Ho controllato il mio file di log e abbiamo trovato questo: 2011-06-27 14: 03: 59.852 [10] DEBUG NHibernate.Impl.AbstractSessionImpl - arruolato nella transazione DTC: Serializable

prima di qualsiasi SQL è stato eseguito sulla connessione. Farò un test unitario per confermare la corretta esecuzione. Non sono troppo sicuro di ciò che serializza mi sta dicendo se

2

La risposta dei bradi, utilizzando un TransactionScope esterno e una transazione interna NHibernate con enlist = dynamic, non sembra funzionare correttamente. Ok, i dati vengono commessi.

Ma se si omette scope.Complete() o si genera un'eccezione dopo tx.Commit() i dati vengono comunque impegnati (per Oracle)! Tuttavia, per qualche motivo questo funziona per SQL-Server.

Le transazioni di NHibernate si occupano di auto-flush ma alla fine chiamano la transazione ADO.NET sottostante. Mentre molte fonti incoraggiano lo schema sopra descritto come best practice per NHibernate per risolvere lo auto-flush issue, le fonti che discutono su ADO.NET nativo dicono il contrario: NON utilizzare TransactionScope e le transazioni interne insieme, non per Oracle e non per SQL-Server. (Vedere this question e my answer)

mia conclusione: Non combinare le transazioni TransactionScope e NHibernate. Per utilizzare TransactionScope, ignorare le transazioni NHibernate e gestire manualmente lo svuotamento (vedere anche NHibernate Flush doc).

0

Da NHibernate libro di cucina

Ricordate che NHibernate richiede una transazione NHibernate quando si interagisce con il database. TransactionScope non è un sostituto. Come illustrato nella prossima immagine, TransactionScope dovrebbe circondare completamente sia la sessione sia la transazione NHibernate. La chiamata a TransactionScope.Complete() dovrebbe verificarsi dopo che la sessione è stata eliminata. Qualsiasi altro ordine causerà molto probabilmente brutti bug di interruzione della produzione come perdite di connessione.

La mia opinione è anche che dovrebbe funzionare con TransactionScope, ma non lo fa, né in 3.3.x.x né nella versione 4.0.0.400.

La ricetta di cui sopra può funzionare, ma hanno bisogno di testarlo con TrancactionScope nidificato, con TransactionScope interiore che ha un Transaction.Suppress definito (quando si utilizza SQL), ecc ...

Problemi correlati