Search code examples
nhibernatesql-server-2008transactionssql-server-2000msdtc

Why would there be no active transaction in the NHibernate IPreUpdateEventListener/IPreInsertEventListener?


I am using NHibernate 3. My application works fine when run against SQL Server 2008 but has intermittent errors on SQL 2000 (we've changed the NH dialect appropriately). The errors are all related to the MDTC (distributed transaction) component. Typically reads work okay but the code blows up during save/update but not always with the same error. One we've seen often is, 'Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction.'.

I am investigating the root causes of this and have added some logging. I have IPreUpdateEventListener and IPreInsertEventListener interceptors defined so I log in there as well as in my repository. What I am finding is that by the time I get to my listener, there is no transaction on the current session.

Here is my repository code:

public virtual void Save(object entity)
{
    logger.DebugFormat("Opening transaction to save entity type {0}.", entity.GetType().Name);

    using (var t = new TransactionScope())
    {
        GetSession().SaveOrUpdate(entity);
        logger.DebugFormat("Committing transaction.");
        t.Complete();
    }
}

And here is my event listener code:

logger.DebugFormat("Save/Insert entity. Transaction.Active = {0}", 
    persister.Factory.GetCurrentSession().Transaction != null 
    ? persister.Factory.GetCurrentSession().Transaction.IsActive.ToString()
    : "no transaction");

And here is the log output:

2011-01-14 17:23:13,549 [9] DEBUG BaseRepository`1.Save - Opening transaction to save entity type XXXXXXX.
2011-01-14 17:23:13,566 [9] DEBUG BaseRepository`1.Save - Committing transaction.
2011-01-14 17:23:13,598 [9] DEBUG AuditEventListener.Audit - Save/Insert entity. Transaction.Active = False

Can you see anything wrong with this? Why is there no transaction active in pre-insert? Does anyone know of anything special I need to do for Sql Server 2000 (MSDTC is switched on)?

Note that the 2008 environment is my local machine running Windows 7 and the Sql Server 2000 server is Server 2003.


Solution

  • TransactionScope does not create a NHibernate transaction.

    You have to create it explicitly, using session.BeginTransaction(). It will be automatically enlisted in the distributed transaction (don't forget to Commit() it before Complete)