Many developers prefer the repository pattern over data access objects. In this recipe, I'll show you how to set up the repository pattern with NHibernate.
Set up the Eg.Core
project with the model and mappings from Chapter 1.
Eg.Core.Data
.Eg.Core
project in Chapter 1.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); }
Eg.Core.Data.Impl
.Eg.Core
and Eg.Core.Data
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 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(); } protected virtual void Transact(Action action) { Transact<bool>(() => { action.Invoke(); return false; }); }
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) { Transact(() => session.Save(item)); } public bool Contains(T item) { if (item.Id == default(Guid)) return false; return Transact(() => session.Get<T>(item.Id)) != null; } public int Count { get { return Transact(() => session.Query<T>().Count()); } } public bool Remove(T item) { Transact(() => session.Delete(item)); return true; } public IEnumerator<T> GetEnumerator() { return Transact(() => session.Query<T>() .Take(1000).GetEnumerator()); } IEnumerator IEnumerable.GetEnumerator() { return Transact(() => GetEnumerator()); } }
The repository pattern, as explained in http://martinfowler.com/eaaCatalog/repository.htm, has two key features:
In this recipe, we are concerned only with 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.
Because 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 the automatic transaction wrapping explained in the previous recipe.
NHibernateRepository
simply implements the members of IRepository<T>
.
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 like
Merge
, Refresh
, and Load
, or allow them to leak through the abstraction.