2010-09-22 20 views
5

El siguiente fragmento de código funciona bien con SQL Server 2008 (SP1) pero con Oracle 11g la llamada a session.BeginTransaction() arroja una excepción con el mensaje 'La conexión ya es parte de un local o un transacción distribuida '(el seguimiento de la pila se muestra a continuación). Usando el '"NHibernate.Driver.OracleDataClientDriver".NHibernate TransactionScope problema con Oracle 11g

¿Alguien más se ha topado con esto?

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) 

Respuesta

0

Una pregunta, ¿por qué haces el interior session.BeginTransaction - desde 2.1 GA NHibernate inscribirá automáticamente en contextos TransactionScope así que no hay razón para hacer su propia más.

+3

Puede ser que sea para conseguir la descarga automática de NHibernate para trabajar apropiadamente – Konstantin

7

El problema de usar sólo el ámbito de transacción se describe aquí: NHibernate FlushMode Auto Not Flushing Before Find

Parece nhibernate (v3.1 con el dialecto de Oracle 11g y db w/opd.net v2.112.1.2) requiere que es operaciones por cuenta propia para evitar el problema de enrojecimiento, pero no he podido lograr que el alcance de la transacción funcione con las transacciones de nhibernate.

Me parece que no puede conseguir que funcione :( esto podría ser un defecto en nhibernate o odp.net, no estoy seguro ...

encontró mismo problema aquí: NHibernate 3.0: TransactionScope and Auto-Flushing

FIJO : encontré una solución! al poner "enlist = dynamic;" en mi cadena de conexión oráculo, el problema se resolvió. He podido usar tanto la transacción nhibernate (para corregir el problema de descarga) como el alcance de la transacción:

 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(); 
     } 

Revisé mi archivos de registro y encontramos este: 2011-06-27 14: 03: 59,852 [10] DEBUG NHibernate.Impl.AbstractSessionImpl - dado de alta en la transacción DTC: Serializable

antes de cualquier SQL fue ejecutado en la conexión. Haré una prueba unitaria para confirmar la ejecución correcta. No estoy seguro de lo serializable que me dice aunque

2

La respuesta de Brads, usando un TransactionScope externo y una transacción interna de NHibernate con enlist = dynamic, no parece funcionar correctamente. Ok, los datos se comprometen.

Pero si omite el scope.Complete() o genera una excepción después de tx.Commit() los datos aún se comprometen (para Oracle)! Sin embargo, por alguna razón esto funciona para SQL-Server.

Las transacciones de NHibernate se encargan de la limpieza automática, pero al final llaman a la transacción ADO.NET subyacente. Mientras que muchas fuentes alientan el patrón anterior como la mejor práctica para NHibernate para resolver el auto-flush issue, las fuentes que discuten ADO.NET nativo dicen lo contrario: NO utilice TransactionScope y transacciones internas juntas, no para Oracle y no para SQL-Server. (Ver this question y my answer)

Mi conclusión: No combine las transacciones TransactionScope y NHibernate. Para usar TransactionScope, omita las transacciones de NHibernate y maneje la descarga manualmente (consulte también NHibernate Flush doc).

0

De NHibernate libro de cocina

Recuerde que NHibernate NHibernate requiere una transacción en la interacción con la base de datos. TransactionScope no es un sustituto. Como se ilustra en la imagen siguiente, TransactionScope debe rodear por completo tanto la sesión como la transacción de NHibernate. La llamada a TransactionScope.Complete() debería producirse después de que la sesión haya sido eliminada. Cualquier otro orden muy probablemente resulte en errores desagradables de producción, como fugas de conexión.

Mi opinión es que también debería funcionar con TransactionScope, pero no, ni en 3.3.x.x ni en la versión 4.0.0.400.

La receta anterior podría funcionar, pero tienen que probarlo con TrancactionScope anidada, con TransactionScope interior que tiene una Transaction.Suppress definido (cuando se utiliza SQL), etc ...

Cuestiones relacionadas