views:

199

answers:

1

Ok, I know nhibernate supports ambient transactions, because nhibernate sessions enlists in the ambient transactions while inside a transaction scope. However, there are some oddities, consider the following test:

    [Test]
    public void Transaction_RollsBackTransactionInsideOfAmbientTransaction_AmbientTransactionAborted()
    {
        // arrange
        ISessionFactory sessionFactory = SessionFactoryOneTimeInitializer.GetTestSessionFactory();
        ISession session = sessionFactory.OpenSession();
        SessionFactoryOneTimeInitializer.CreateDataBaseSchemaIfRequiredByConfiguration(session);

        using (new TransactionScope())
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                // act
                transaction.Rollback();
            }

            // assert
            Assert.AreEqual(TransactionStatus.Aborted, Transaction.Current.TransactionInformation.Status); 
        }
    }

This test fails. How will nhibernate ensure that the ambient transaction is not persisted to the database?

+1  A: 

I know relatively well how Hibernate work with JTA in the Java world, but I am not a .NET expert. Your question nevertheless caught my attention.

In Java, you need to configure Hibernate with either JDBC or JTA transaction. In which case, the Transaction object returned by Hibernate wraps either a transaction that is bound to one database connection (JDBC) or the global transaction that is thread-local. The global thread-local transaction context can be invalidated using UserTransaction#setRollbackOnly, which ensures it will never commit succesfully. It's however preferable to not manage transaction through Hibernate but to use solely the UserTransaction object provided by JTA.

This still seems to be the same in NHibernate and there is two transaction factories. One for distributed transactions and one for local transactions. But both return an AdoTransaction:

public ITransaction CreateTransaction(ISessionImplementor session)
{
    return new AdoTransaction(session);
}

This doesn't seem to be consistent in case of distributed / ambient transactions. I don't see how rollback would work in this case given that the global transaction context can not be invalided in .NET (so far I understand), and AdoTransaction seems to represent a transaction on database connection.

So I feel like the answer to your question is "it won't" which would explain that your test fails. This means that you should not manage transaction through NHiberate if you use ambient transaction. Just like it's not a recommended practice with Hibernate and JTA.

EDIT

See also this question: http://stackoverflow.com/questions/494550/how-does-transactionscope-roll-back-transactions

ewernli