NHibernate – Repository pattern

I know that there allready are implementations for NHibernate-based repositories (eg. RhinoTools) but I can’t help to fiddling a bit with a design that I feel comfortable with. When building business applications I like to use a domain model (Read more – Martin Fowler) and to use repositories (Read more – Martin Fowler) for storing my domain objects. When designing we storage-layer (data-access-layer) I always define each repository using an Interface. This is something I do to be able to create fakes and mocks of my repositories; as well as create different implementations of them, e.g. one using NHibernate and another using SubSonic etc. Each implementation has it’s base-classes etc. just to get rid of repetitive boilerplate coding. For my NHibernate base implementation it looks something like this:

NHibContext (see earlier post) is responsible for creating NHibSessions (which is a wrapper around an NHibernate.ISession). The NHibContext is injected in my NHibRepository so that it can create a NHibSession for use within the repository (this is probably something that might get changed and instead a NHibSession will be injected directly). Than I create e.g. a NHibUserAccountRepository that extends the NHibRepository and also implements the IUserAccountRepository. Lets pick it apart.

Why IRepository?
I want a common repository interface independent of which underlying storage framework is used or what domain object I’m dealing with.

public interface IRepository<T> where T : class, IEntity
{
    void Commit();
    void Rollback();

    void Insert(T item);
    void Update(T item);
    void Delete(T item);

    T SingleBy(Expression<Func<T, bool>> query);

    IList<T> List();
    IList<T> ListBy(Expression<Func<T, bool>> query);
}

Why IUserAccountRepository?
As I said before, I want to be able to create fakes and mocks of my repositories and I want to be able to use polymorphism when dealing with my domain-object-specific repositories, so that I can work against an interface, independent of the actual implementation.

public interface IUserAccountRepository : IRepository<UserAccount>
{
}

Why NHibRepository
I want a strongly typed repository-base that keeps me from writing boilerplate code in all my specific NHibernate-based repositories.

public abstract class NHibRepository<T> : IRepository<T>, IDisposable
    where T : class, IEntity
{
    protected NHibContext Context { get; private set; }
    protected NHibSession Session { get; private set; }

    protected NHibRepository(NHibContext context)
    {
        Context = context;
        Session = Context.CreateNewSession();
    }

    public void Dispose()
    {
        Disposer.TryDispose(Session);
    }

    public void Commit()
    {
        Session.Commit();
    }

    public void Rollback()
    {
        Session.Rollback();
    }

    public virtual void Insert(T item)
    {
        Session.Insert<T>(item);
    }

    public virtual void Update(T item)
    {
        Session.Update<T>(item);
    }

    public virtual void Delete(T item)
    {
        Session.Delete<T>(item);
    }

    public virtual T SingleBy(Expression<Func<T, bool>> query)
    {
        return Session.GetItemBy<T>(query);
    }

    public virtual IList<T> List()
    {
        return Session.GetList<T>();
    }

    public virtual IList<T> ListBy(Expression<Func<T, bool>> query)
    {
        return Session.GetListBy<T>(query);
    }        
}

UserAccountRepository against NHibernate

public class UserAccountRepository : NHibRepository<UserAccount>, IUserAccountRepository
{
    public UserAccountRepository(NHibContext context)
        : base(context)
    {}
}

Why NHibSession?
Simple. I want a slimmer and unified interface for interacting with the NHibernate-core and I want it to take care of transactions.

public class NHibSession
    : IDisposable
{
    private ISession InnerSession { get; set; }
    private ITransaction Transaction { get; set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="NHibSession"/> class.
    /// </summary>
    /// <param name="session">The session.</param>
    public NHibSession(ISession session)
    {
        InnerSession = session;
        InnerSession.FlushMode = FlushMode.Commit;
        SetupNewTransaction();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (Transaction != null)
            {
                Transaction.Rollback();
                Transaction.Dispose();
                Transaction = null;
            }

            if (InnerSession != null)
            {
                InnerSession.Dispose(); //InnerSession.Close(); Do not use! It breaks when outer transactionscopes are active! Should only use Dispose.
                InnerSession = null;
            }                
        }
    }

    ~NHibSession()
    {
        Dispose(false);
    }

    public void Commit()
    {
        Transaction.Commit();
        SetupNewTransaction();
    }

    public void Rollback()
    {
        Transaction.Rollback();
        SetupNewTransaction();
    }

    private void SetupNewTransaction()
    {
        if (Transaction != null)
            Transaction.Dispose();

        Transaction = InnerSession.BeginTransaction();
    }

    /// <summary>
    /// Creates and returns a Query.
    /// </summary>
    /// <param name="queryString">The query string.</param>
    /// <returns></returns>
    public IQuery CreateQuery(string queryString)
    {
        return InnerSession.CreateQuery(queryString);
    }

    /// <summary>
    /// Creates and returns a Criteria.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public ICriteria CreateCriteria<T>()
        where T : class
    {
        return InnerSession.CreateCriteria<T>();
    }

    /// <summary>
    /// Gets an item that matches sent expression.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="query">The query.</param>
    /// <returns></returns>
    public T GetItemBy<T>(Expression<Func<T, bool>> query)
    {
        return InnerSession.Linq<T>().SingleOrDefault(query);
    }

    /// <summary>
    /// Returns item via Id.
    /// </summary>
    /// <typeparam name="TReturn"></typeparam>
    /// <typeparam name="TId"></typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    public TReturn GetItemById<TReturn, TId>(TId id)
    {
        return InnerSession.Get<TReturn>(id);
    }

    /// <summary>
    /// Returns item via NHibernate Criterions.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="criterions"></param>
    /// <returns></returns>
    public T GetItemByCriterions<T>(params ICriterion[] criterions)
    {
        return AddCriterions(InnerSession.CreateCriteria(typeof(T)), criterions).UniqueResult<T>();
    }

    /// <summary>
    /// Returns a list of ALL items.
    /// </summary>
    /// <remarks>ALL items are returned.</remarks>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public IList<T> GetList<T>()
    {
        return GetListByCriterions<T>(null);
    }

    /// <summary>
    /// Returns a list of items matching sent expression.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="query">The query.</param>
    /// <returns></returns>
    public IList<T> GetListBy<T>(Expression<Func<T, bool>> query = null)
    {
        return InnerSession.Linq<T>().Where(query).ToList();
    }

    /// <summary>
    /// Returns list of item matching sent criterions.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="criterions"></param>
    /// <returns></returns>
    public IList<T> GetListByCriterions<T>(params ICriterion[] criterions)
    {
        ICriteria criteria = AddCriterions(InnerSession.CreateCriteria(typeof(T)), criterions);
        IList<T> result = criteria.List<T>();

        return result ?? new List<T>(0);
    }

    /// <summary>
    /// Deletes sent item.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    public void Delete<T>(T obj)
    {
        InnerSession.Delete(obj);
    }

    /// <summary>
    /// Deletes sent item by id.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TId"></typeparam>
    /// <param name="id"></param>
    public void DeleteById<T, TId>(TId id)
    {
        Delete(GetItemById<T, TId>(id));
    }

    /// <summary>
    /// Deletes by query.
    /// </summary>
    /// <param name="query"></param>
    public void DeleteByQuery(string query)
    {
        InnerSession.Delete(query);
    }

    /// <summary>
    /// Inserts sent item.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    public void Insert<T>(T obj)
    {
        InnerSession.Save(obj);
    }

    /// <summary>
    /// Updates sent item.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    public void Update<T>(T obj)
    {
        InnerSession.Update(obj);
    }

    private static ICriteria AddCriterions(ICriteria criteria, ICriterion[] criterions)
    {
        if (criterions != null)
            for (int c = 0; c < criterions.Length; c++)
                criteria = criteria.Add(criterions[c]);

        return criteria;
    }
}

Consume it
To show you how I consume it, let me show you a simple test.

[TestMethod]
public void CanInsertSingleUserAccount()
{
    var newUserAccount = CreateUserAccount();

    IUserAccountRepository userRepository = CreateRepository();
    userRepository.Insert(newUserAccount);
    userRepository.Commit();

    Assert.AreEqual(1, StorageTestHelper.RowCount(UserAccountsTableName));
}

private static IUserAccountRepository CreateRepository()
{
    return new UserAccountRepository(StorageTestHelper.NHibContext);
}

Thats it. Hope you find it inspiring.

//Daniel

About these ads

15 thoughts on “NHibernate – Repository pattern

  1. Pingback: Repository Pattern « Randomos Technos

  2. Could you plz show me how to use these methods and how can i pass parameter values to each method.

    public T GetItemBy(Expression<Func> query)
    public T GetItemByCriterions(params ICriterion[] criterions)
    public IList GetListBy(Expression<Func> query = null)
    public IList GetListByCriterions(params ICriterion[] criterions)

    • Hi,

      Some old code of mine, but for GetItemBy() and GetListBy() you would do:

      GetItemBy(uac => uac.Email == "daniel@none.com");
      

      For the functions that takes NHibernate ICriterions, you would simply create one, eg. by:

      GetItemByCriterions(Expression.Eq("Email", "daniel@none.com"))
      

      //Daniel

    • Hi,

      Don’t know why I didn’t provice ZIP’s with the complete code. Actually having a hard time finding it know, but:

      /// <summary>
      /// Helps with some disposing and closing operations
      /// depending on sent type.
      /// </summary>
      public static class Disposer
      {
          /// <summary>
          /// Disposes sent object.
          /// </summary>
          /// <param name="obj"></param>
          public static void DisposeInstance(IDisposable obj)
          {
              if (obj == null)
                  return;
      
              DbCommand dbCmd;
              DbConnection dbCn;
              DbDataReader dbDrdr;
              Stream strm;
              TextReader txtRdr;
      
              dbCmd = obj as DbCommand;
              if (dbCmd != null)
              {
                  DisposeDbCommand(dbCmd);
                  return;
              }
      
              dbCn = obj as DbConnection;
              if (dbCn != null)
              {
                  DisposeDbConnection(dbCn);
                  return;
              }
      
              dbDrdr = obj as DbDataReader;
              if (dbDrdr != null)
              {
                  DisposeDataReader(dbDrdr);
                  return;
              }
      
              strm = obj as Stream;
              if (strm != null)
              {
                  DisposeStream(strm);
                  return;
              }
      
              txtRdr = obj as TextReader;
              if (txtRdr != null)
              {
                  DisposeTextReader(txtRdr);
                  return;
              }
      
              DoDispose(obj);
          }
      
          /// <summary>
          /// Closes and disposes sent datareader.
          /// </summary>
          /// <param name="reader"></param>
          public static void DisposeDataReader(IDataReader reader)
          {
              if (reader == null)
                  return;
      
              reader.Close();
              DoDispose(reader);
          }
      
          /// <summary>
          /// Disposes sent dbcommand, will not explicity close the connection.
          /// </summary>
          /// <param name="cmd"></param>
          public static void DisposeDbCommand(DbCommand cmd)
          {
              DisposeDbCommand(cmd, false);
          }
      
          /// <summary>
          /// Disposes sent dbcommand.
          /// </summary>
          /// <param name="cmd"></param>
          /// <param name="explicityCloseConnection">Defines if cmd.Connection.Close should be called.</param>
          public static void DisposeDbCommand(DbCommand cmd, bool explicityCloseConnection)
          {
              if (cmd == null)
                  return;
      
              if (cmd.Connection != null && explicityCloseConnection && cmd.Connection.State != ConnectionState.Closed)
                  cmd.Connection.Close();
      
              DoDispose(cmd);
          }
      
          /// <summary>
          /// Closes and disposes sent connection.
          /// </summary>
          /// <param name="connection"></param>
          public static void DisposeDbConnection(DbConnection connection)
          {
              if (connection == null)
                  return;
      
              connection.Close();
              DoDispose(connection);
          }
      
          /// <summary>
          /// Closes and Disposes the sent text reader.
          /// </summary>
          /// <param name="reader">The reader.</param>
          public static void DisposeTextReader(TextReader reader)
          {
              if (reader == null)
                  return;
      
              reader.Close();
              DoDispose(reader);
          }
      
          /// <summary>
          /// Closes and Disposes the stream.
          /// </summary>
          /// <param name="stream">The stream.</param>
          public static void DisposeStream(Stream stream)
          {
              if (stream == null)
                  return;
      
              stream.Close();
              DoDispose(stream);
          }
      
          /// <summary>
          /// Disposes sent object, but only if it implements IDisposable.
          /// </summary>
          /// <remarks>
          /// If you know that the object implements IDisposable, then
          /// use specific Dispose instead.
          /// </remarks>
          /// <param name="obj"></param>
          public static void DisposeObject(object obj)
          {
              IDisposable x = (obj as IDisposable);
              if (x == null)
                  return;
      
              DisposeInstance(x);
          }
      
          private static void DoDispose(IDisposable obj)
          {
              obj.Dispose();
          }
      }
      

      //Daniel

  3. Thanks for the response.
    I wish your posts were higher in search results.
    I took an arcane search term to lead me to you.
    Again very helpful.

  4. Hi here
    This tutorial seems one of the best i´ve found but i dont seem to get it to compile
    Please complete example project :|

  5. Hello !!

    Thank’s for the simplicity and the quality of you article. I really apreciate the reusable benefit on th DRY when you creating an abstract class to server as base respository class.

    While triying to do it myself, i got the idea to make all my Entity framework classes inherit from a Common class called Identifiable. This class only focus on the capability of classes to have an Id(mapped to the corresponding unique Id in database).

    Since ia can identify every object with its Id, i can implement a concrete method GetById() like this :

    public T GetById(int id)
    {
    return this.Context.Set().Single(p => p.ID == id);

    }

    And finally i just have one an generic Class GenericRepository to manage my domain model.

  6. Its really a comprehensive use of Nhibernate with Repository pattern. Really enjoyed reading it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s