« Monospace Open Space Friday Schedule | Main | Bootstrapping NHibernate with StructureMap »
Wednesday
Oct142009

NHibernate Transactional Boundaries

In NHibernate Bootstrapping with StructureMap, I did not address the issue of transactional boundaries. The example had very simple controller actions that managed their own commits. However, this question on StackOverflow left me wondering who should be responsible for the commit?

Sharp Architecture’s Approach

Sharp Architecture is an excellent “architectural foundation for building maintainable web applications with ASP.NET MVC”. It has an Action Filter called Transaction that starts a transaction in the OnActionExecuting event, and then commits if no exception occurred. Otherwise, it explicitly rolls the transaction back. In fact, the Implicit transactions thread in the Sharp Architecture Google group discusses the Transaction attribute and some of the issues using it. The Transaction attribute provides the functionality that I want, but it requires the developer to decorate each Action method with an attribute. Why not make the HttpModule that creates and disposes of the Unit of Work handle the commit?

Modified Bootstrapping Example

I have modified the Bootstrapping NHibernate with StructureMap example from my previous post to do just that. Now, the NHibernateModule is responsible for calling Commit() on the UnitOfWork. Here is the NHibernateModule’s new Dispose method:

public void Dispose()
{
    _unitOfWork.Commit();
    _unitOfWork.Dispose();
}

The only addition is the call to the _unitOfWork.Commit(). However, now that the NHibernateModule is responsible for the commit, the developer can not abort an existing transaction. So, I added a Rollback() method to the IUnitOfWork class. The concrete implementation, UnitOfWork, calls _transaction.Rollback().

One final change to the UnitOfWork prevents it from throwing an exception if the developer explicitly calls commit by checking the ITransaction’s IsActive property before attempting to commit. Here is the UnitOfWork’s new Commit method:

public void Commit()
{
    if (_transaction.IsActive)
        _transaction.Commit();
}

Multi-Transaction Unit of Work

There is still one issue nagging at me. Once the developer commits the unit of work, the transaction is closed. The FubuTasks example in the fubumvc-contrib project solves this problem by starting a new transaction once the existing transaction is committed. Here is the source for FubuTask’s NHibernateUnitOfWork. I have talked to Chad Myers about this implementation and he has moved away from the idea of handling rollback in general. In any event, I don’t like the idea of starting a new transaction because I don’t think there should be one transaction per request. At the same time, I am preventing the developer from using my unit of work for more than one transaction. At least for now, opening a new transaction is a YAGNI for me. What do you think?

The full source code with these changes are available in the mvbalaw-commons project here.

Tags:

kick it on DotNetKicks.com

PrintView Printer Friendly Version

EmailEmail Article to Friend

References (1)

References allow you to track sources for this article, as well as articles that were written in response to this article.

Reader Comments (3)

I remember Ayende has been having certain problems with using a HttpModule. Something like calling Dispose several times per request, or similar. Anyway, keeping all initialization/finalization logic in a single place (HttpApplication) looks cleaner, what you think?

October 26, 2009 | Unregistered Commenterulu

Hi
One transaction per request is not possible for some situations. Example: creating new invoice need generate new number. Number generator use database. Generator should quick generate new number and commit transaction. Then we can create new invoice. That 2 transactions per request.

You shouldn't holding generator lock within transaction too long.

January 6, 2010 | Unregistered Commenterdario-g

Yes, you said well that The only addition is the call to the _unitOfWork.Commit(). However, now that the NHibernateModule is responsible for the commit, the developer can not abort an existing transaction.

April 1, 2010 | Unregistered CommenterJulius

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>