NHibernate: No implicit transactions

We assume the reader knows that NHibernate is one of the best ORM’s build for .NET.

Implicit transactions are discouraged

Generally “implicit transactions are discouraged” (ref: http://www.google.nl/search?hl=nl&q=implicit+transactions+are+discouraged)

However, webservices can be build by simply opening up an NHibernate session whenever a new webCall arrives at the server. Than simply handle all data manipulation and closing the NHibernate session when the webCall ends. THis is usually done when the context for the service is going to be setup during inputfilters and outputfilters, or if you work with WCF using things like custom Behaviors.

The problem with this is that it makes reads from the database as well as updates to the database kind of uncontrollable. If you use implicit transactions you really never know for sure what object updates cause SQL update statements to the database. This of course is not a good thing.

When using an ORM like NHibernate we really should be using explicit transactions, even for database read actions.

We can describe this wish using the following example user stories:

To be able to support NHibernate second level cache,
all read actions should be written
with explicit transactions.

or:

To better control what is updated in the database
we need to prevent NHibernate properties registered as ‘dirty’
by the NHibernate framework therefore we
need to use explicit transactions when writing,
updating or reading from the database

Example of the difference

So what is this all about really? Well here is an example of the difference for a reading action:

This first piece of code that assumes an NHibernate session is already opened thus considered an implicit transaction

public List FinAirportLocationList(string nameCriterium, ... )
{
  //get current session
  ISession session = HaddockSession.Current.CurrentSession;
  //construct query
  string queryString = @"select l from Location l inner join fetch l.Names as names where names.Text      
like :searchcriteria";
  IQuery query = session.CreateQuery(queryString);
  query.SetString("searchcriteria", nameCriterium + "%");
  query.SetCacheable(true);
  IList list = query.List();
  return list;
}

Here is an example that reads data with an explicit transaction:

public   IList GetAllLocations()
{
  IList locationList;
  using (ISession session = HaddockSession.SessionFactory.OpenNewSession())           
  {                
     using (ITransaction transaction = SessionFactory.BeginTransaction())
     {
       IQuery query = session.CreateQuery("select l from Location l inner join fetch l.Names as names");
       locationList = query.List();
       transaction.Commit();  // always commit: needed for 2nd level cache
     }
   }
 
   return  locationList;
}

Note that this example wiil have to enable access to the Nhibernate sessionfactory. This Sessionfactory will need to be controlled per application.

Benefits of explicit transactions are:

  • It closes the NHibernate session when the using-block ends. Note that this does not support any further lazy-loading but prevents lingering sessions to exist.
  • It drives developers into awareness when database access is happening. This is especially important to ; make roles explicit.
  • of course also important for awareness of performance of your application
  • Explicit transactions for read access enables the possibility to use NHibernate second level cache.
  • Creates awareness what is necessary to load during a transaction. This is because when a session is closed, lazy-loaded properties/lists will not be loaded automatically anymore by NHibernate. Note the small ‘fetch’ statement in the above example: it pre-fetches the names collection of Locations.
  • It makes clear what your root-aggregates are and how you want to load these.

And for the sake of more detailed information: A good example how to configure 2nd level cache for NHibernate can be found on gitshah.com.

Conclusion: Do not fall for the trap of using implicit transactions with NHibernate. When you start with NHibernate as your ORM, start with explicit transactions. See if you can use the Unit of Work pattern for NHibernate if you need it for user stories that need to update multiple objects during one webcall.