Setting up an NHibernate repository

Many developers prefer the repository pattern to data access objects. In this recipe, we will show you how to set up the repository pattern with NHibernate.

Getting ready

Set up the Eg.Core project with the model and mappings from Chapter 2, Models and Mappings.

How to do it…

  1. Create a new and empty class library project named Eg.Core.Data.
  2. Add a reference to Eg.Core project in Chapter 2, Models and Mappings.
  3. Add the following IRepository interface:
    public interface IRepository<T>: IEnumerable<T>
      where T : Entity 
    { 
      void Add(T item);
      bool Contains(T item);
      int Count { get; }
      bool Remove(T item);
    }
  4. Create a new and empty class library project named Eg.Core.Data.Impl.
  5. Add references to the Eg.Core and Eg.Core.Data projects.
  6. Add a new abstract class named NHibernateBase using the following code:
    protected readonly ISessionFactory _sessionFactory;
    
    protected virtual ISession session
    {
      get
      {
        return _sessionFactory.GetCurrentSession();
      }
    }
    
    public NHibernateBase(ISessionFactory sessionFactory)
    {
      _sessionFactory = sessionFactory;
    }
    
    protected virtual 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();
    }
    
    protected virtual void WithinTransaction(Action action)
    {
      WithinTransaction<bool>(() =>
      {
        action.Invoke();
        return false;
      });
    }
  7. Add a new class named NHibernateRepository using the following code:
    public class NHibernateRepository<T> : 
      NHibernateBase,
      IRepository<T> where T : Entity
    {
    
      public NHibernateRepository(
        ISessionFactory sessionFactory)
        : base(sessionFactory)
      {
      }
    
      public void Add(T item)
      {
        WithinTransaction(() => session.Save(item));
      }
    
      public bool Contains(T item)
      {
        if (item.Id == default(Guid))
          return false;
        return WithinTransaction(() => 
          session.Get<T>(item.Id)) != null;
      }
    
      public int Count
      {
        get
        {
          return WithinTransaction(() => 
            session.Query<T>().Count());
        }
      }
    
      public bool Remove(T item)
      {
        WithinTransaction(() => session.Delete(item));
        return true;
      }
    
      public IEnumerator<T> GetEnumerator()
      {
        return WithinTransaction(() => session.Query<T>()
               .Take(1000).GetEnumerator());
      }
    
      IEnumerator IEnumerable.GetEnumerator()
      {
        return WithinTransaction(() => GetEnumerator());
      }
    
    }

How it works…

The repository pattern, as explained in https://martinfowler.com/eaaCatalog/repository.html, has two key features:

  • It behaves as an in-memory collection
  • Query specifications are submitted to the repository for satisfaction

In this recipe, we are concerned with only the first feature: behaving as an in-memory collection. The remaining recipes in this chapter will build on this base and show various methods for satisfying the second point.

As our repository should act like an in-memory collection, it makes sense that our IRepository<T> interface should resemble ICollection<T>.

Our NHibernateBase class provides both contextual session management and automatic transaction wrapping, as explained in the previous recipe.

NHibernateRepository simply implements the members of IRepository<T>.

There's more…

The repository pattern reduces data access to its absolute simplest form, but this simplification comes with a price. We lose much of the power of NHibernate behind an abstraction layer. Our application must either do without even basic session methods such as Merge, Refresh, and Load, or allow them to leak through the abstraction.

See also

  • Transaction auto-wrapping for the data access layer
  • Using named queries in the data access layer
  • Using ICriteria in the data access layer
  • Using paged queries in the data access layer
  • Using LINQ specifications in the data access layer
..................Content has been hidden....................

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