Transaction Auto-wrapping for the data access layer

In this recipe, I'll show you how we can set up the data access layer to wrap all data access in NHibernate transactions automatically.

Getting ready

Complete the Eg.Core model and mappings from Chapter 1.

How to do it...

  1. Create a new class library named Eg.Core.Data.
  2. Add a reference to NHibernate.dll and the Eg.Core project.
  3. Add the following two DAO classes:
    public class DataAccessObject<T, TId>
      where T : Entity<TId>
    {
    
      private readonly ISessionFactory _sessionFactory;
    
      private ISession session
      {
        get
        {
          return _sessionFactory.GetCurrentSession();
        }
      }
    
      public DataAccessObject(ISessionFactory sessionFactory)
      {
        _sessionFactory = sessionFactory;
      }	
    
      public T Get(TId id)
      {
        return Transact(() => session.Get<T>(id));
      }
    
      public T Load(TId id)
      {
        return Transact(() => session.Load<T>(id));
      }
    
      public void Save(T entity)
      {
        Transact(() => session.SaveOrUpdate(entity));
      }
    
      public void Delete(T entity)
      {
        Transact(() => session.Delete(entity));
      }
    
      private TResult Transact<TResult>(Func<TResult> func)
      {
        if (!session.Transaction.IsActive)
        {
          // Wrap in transaction
          TResult result;
          using (var tx = session.BeginTransaction())
          {
            result = func.Invoke();
            tx.Commit();
          }
          return result;
        }
    
        // Don't wrap;
        return func.Invoke();
      }
    
      private void Transact(Action action)
      {
        Transact<bool>(() =>
        {
    
    
          action.Invoke();
          return false;
        });
      }
    
    }
    
    public class DataAccessObject<T>
      : DataAccessObject<T, Guid>
      where T : Entity
    {
    }

How it works...

NHibernate requires that all data access occurs inside an NHibernate transaction. As we saw with the Transaction action filter recipe in Chapter 4, this can be easily accomplished with AOP.

Note

Remember, the ambient transaction created by TransactionScope is not a substitute for a NHibernate transaction.

This recipe shows a more explicit approach. To ensure that at least all our data access layer calls are wrapped in transactions, we create a private Transact function that accepts a delegate, consisting of some data access methods, such as session.Save or session.Get . This Transact function first checks if the session has an active transaction. If it does, Transact simply invokes the delegate. If it doesn't, it creates an explicit NHibernate transaction, then invokes the delegate, and finally commits the transaction. If the data access method throws an exception, the transaction will be rolled back automatically as the exception bubbles up through the using block.

There's more...

This transactional auto-wrapping can also be set up using SessionWrapper from the unofficial NHibernate AddIns project at http://code.google.com/p/unhaddins. This class wraps a standard NHibernate session. By default, it will throw an exception when the session is used without an NHibernate transaction. However, it can be configured to check for and create a transaction automatically, much in the same way I've shown you here. This is the same SessionWrapper we used in the Conversation per Business Transaction recipe in Chapter 3.

See also

  • Setting up an NHibernate repository
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset