Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nhibernate with TransactionScope Error - DTC transaction prepre phase failed -- Upgrade to Nhibernate 3.0

I am getting the following exception when using Nhibernate and ADO.Net operations inside the transaction Scope.Eg. It was fine with Nhibernate 2.1 but now upgraded to 3.0 which throws error.

using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
        GetmemberId(); --> NHibernate Call
        Update(); ADO Call OracleDB
}

Since this acts as ambient transaction, Nhibernate tries to dispose the transaction soon before the outer transaction completes.correct me if I am wrong, Is there any solution because help me , But When I move the Nhibernate call outside TransactionScope everything works fine. The example I have given is sample one, mines involves a more complex one, since I have keep both the calls inside TransactionScope and the error Iam getting is as following,

ERROR 13 NHibernate.Impl.AbstractSessionImpl - DTC transaction prepre phase failed System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Transaction'. at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption) at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent) at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope.Initialize(Transaction transactionToUse, TimeSpan scopeTimeout, Boolean interopModeSpecified) at System.Transactions.TransactionScope..ctor(Transaction transactionToUse) at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment) 2011-02-08 13:41:46,033 ERROR 13 NHibernate.Impl.AbstractSessionImpl - DTC transaction prepre phase failed System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Transaction'. at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption) at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent) at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope.Initialize(Transaction transactionToUse, TimeSpan scopeTimeout, Boolean interopModeSpecified) at System.Transactions.TransactionScope..ctor(Transaction transactionToUse) at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)

like image 768
Prabu Avatar asked Feb 08 '11 06:02

Prabu


2 Answers

Try

Configuration.SetProperty(Environment.TransactionStrategy,"NHibernate.Transaction.AdoNetTransactionFactory")

Or in nhibernate config

<property name="transaction.factory_class">
NHibernate.Transaction.AdoNetTransactionFactory
</property>

It worked for me =)

like image 100
Medion Avatar answered Oct 26 '22 17:10

Medion


We ran into this same error, and it was caused by the way we used sessions and transactions in our Web Api with NHibernate.

We should have been using session-per-request. (This can be a web request or the execution of a NServiceBus handler.) When a request starts, you should open a session and start a transaction.

We were not doing that. In our repositories, we created a new session and transaction for every database request. This meant that rather than having a single session/transaction for a request, we had many.

The root cause of the bug for us was that we were loading an entity (domain model object) in one session, modifying it, and saving it using a different session. By the time NHibernate executed the update call, the loading session/transaction had already been committed, flushed, and closed.

Solution was to pull our session/transaction creation out of the repositories and up to the Controller layer (doable using a HttpModule for REST calls and/or with aspect oriented programming using dependency injection). This one session/transaction then lives for the lifetime of the REST call or NServiceBus handler execution and is used for all database access during that call. When that call ends, it will be committed or rolled back as appropriate.

The answer given above setting the config property simply turns off DTC and reverts to the older way of doing NHibernate transactions. That may solve the problem for you if you never have to scale up your Web Api to multiple instances, but if you do, this will cause you problems.

like image 38
Devin Rose Avatar answered Oct 26 '22 16:10

Devin Rose