Transaction auto-wrapping for the data access layer

In this recipe, we'll show you how to 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 2, Models and Mappings.

How to do it…

  1. Create a new class library named Eg.Core.Data.
  2. Install NHibernate to Eg.Core.Data using the NuGet Package Manager Console.
  3. Add the following two DataAccessObject 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 WithinTransaction(() => session.Get<T>(id));
      }
    
      public T Load(TId id)
      {
        return WithinTransaction(() => session.Load<T>(id));
      }
    
      public void Save(T entity)
      {
        WithinTransaction(() => session.SaveOrUpdate(entity));
      }
    
      public void Delete(T entity)
      {
        WithinTransaction(() => session.Delete(entity));
      }
    
      private TResult WithinTransaction<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 WithinTransaction(Action action)
      {
        WithinTransaction<bool>(() =>
        {
          action.Invoke();
          return false;
        });
      }
    
    }
    
    public class DataAccessObject<T>
      : DataAccessObject<T, Guid>
      where T : Entity
    {
    }

How it works…

NHibernate requires every data access to occur inside a NHibernate transaction. As we saw with the Transaction action filter recipe in Chapter 3, Sessions and Transactions, this can, in some environments, be accomplished with non-intrusive code elements, such as .NET attributes. This technique is sometimes called Aspect Oriented Programming (AOP).

Note

The ambient transaction created by a transaction scope is not a substitute for an NHibernate transaction.

This recipe, however, shows a more explicit approach. To ensure that at least all our data access layers are wrapped in transactions, we create a private WithinTransaction method that accepts a delegate and consists of some data access methods, such as session.Save or session.Get. The WithinTransaction method first checks whether the session has an active transaction. If it does, the delegate is invoked immediately. If it does not, a new NHibernate transaction is created, the delegate is invoked and finally the transaction is carried out. If the data access method throws an exception, the transaction will be rolled back automatically, as the exception bubbles up to the using block.

There's more…

This transactional auto-wrapping can also be set using SessionWrapper from the unofficial NHibernate AddIns project at https://bitbucket.org/fabiomaulo/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 as I have shown you here.

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
18.223.213.238