Home / .NET / What is that all about the repository anti pattern?

What is that all about the repository anti pattern?

There are a lot of discussions going on about the repository pattern. I also started one at the last usergroup meeting together with Julie Lerman. Generally the generic repository is considered an anti pattern as stated by Greg Young, he offers a solution by applying a composition pattern to maximize code reuse. Mike from SapiensWork even calls it a complete anti pattern. Ayende calls it since a long time the new singleton. Ayende also suggests in his older articles to either use directly NHibernate’s ISession or RavenDB’s IDocumentSession. Complex queries should be placed into query objects according to his article. So do we really need a repository? This article tries to answer this question.


Let us look into how a generic repository would look like.

interface IRepository<T> {
IEnumerable<T> FindAllBy(IQuery query);
void Add(T item);
void Delete(T item);
...
}

This approach has the following drawbacks:

  • We need to instantiate for each entity a new repository of T
  • Like Greg states we are losing expressivness when we are using FindAllBy(new CustomerByNameQuery(“Daniel”))

What about when we apply Gregs composition approach?

Public class CustomerRepository {
    private Repository<Customer> internalGenericRepository;
    Public IEnumerable<Customer> GetCustomersWithFirstNameOf(string name) {
         internalGenericRepository.FindAllBy(new CustomerFirstNameOfQuery(name));
    }
}

This would be a bit more expressiv because we have meaningful methods which describe what actually is done instead of FindAllBy(new QueryObject(…)). But still there is one major drawback:

  • We need to instantiate a concrete class for each entity type we want to fetch data from.

Let us try even another approach. What about that repository:

interface IRepository {
IEnumerable<T> FindAllBy(IQuery query)
 where T : Entity;
…
}

We suddenly don’t need to instantiate a repository for each entity. We can fetch data from multiple entities with the same repository instance. But still it has a drawback:

  • It is missing expressivness

How could we overcome this issue? There is actually a solution with extension methods. We can use extension methods to cover the query objects behind the scenes and give this approach more expressivness.

public static class CustomerRepositoryExtensions {
   public static IEnumerable<Customer> GetCustomersWithFirstNameOf(this IRepository repository, string name) {
      return repository.FindAllBy(new CustomerFirstNameOfQuery(name))
   }
}

Now we can have the following:

public class Foo {
   public Foo(IRepository repository) {
      this.repository = repository;
   }
   public void Bar() {
      var customers = this.repository.GetCustomersWithFirstNameOf("daniel");
   }
}

That looks kinda nice. It is easy to test. We don’t need a real database for the Foo class. But stop! What about transaction management and where is the session in case of NHibernate or something similar? In case of NHibernate we can directly use ISessionFactory.GetCurrentSession() to get the current session and then start a transaction.

public class Foo {
   public Foo(ISessionFactory sessionFactory, IRepository repository) {
      this.sessionFactory = sessionFactory;
      this.repository = repository;
   }
   private ISession Session {
      get { return this.sessionFactory.GetCurrentSession(); }
   }
   public void Bar() {
      using(var tx = this.Session.BeginTransaction()) {
         var customers = this.repository.GetCustomersWithFirstNameOf("daniel");
         // modify customers
         tx.Commit();
      }
   }
}

Suddenly we have NHibernate not only in the query objects and the repository implementation (someone needs to pass the current session of the call scope into the query) but also on the business logic. And also we have two dependencies which need to be injected in every class which needs database access. We can solve the first problem with an easy adapter for the session and the transaction which even allows nested scopes:

    public class UnitOfWork : IUnitOfWork
    {
        private readonly Func rootScopeFactory;
        private readonly Func dependentScopeFactory;
        public UnitOfWork(ISessionFactory sessionFactory, Func rootScopeFactory, Func dependentScopeFactory)
        {
			this.sessionFactory = sessionFactory;
            this.rootScopeFactory = rootScopeFactory;
            this.dependentScopeFactory = dependentScopeFactory;
        }
        public IUnitOfWorkScope Start()
        {
            IUnitOfWorkScope scope = !CurrentSessionContext.HasBind(this.sessionFactory)
                                         ? this.rootScopeFactory()
                                         : this.dependentScopeFactory();
            scope.Begin();
            return scope;
        }
    }
	public class UnitOfWorkScope : IUnitOfWorkScope
    {
        public UnitOfWorkRootScope(ISessionFactory sessionFactory)
        {
			this.SessionFactory = sessionFactory;
        }
        protected ISessionFactory SessionFactory { get; private set; }
        protected ISession Session
        {
            get { return this.SessionFactory.GetCurrentSession(); }
        }
        protected ITransaction Transaction
        {
            get { return this.Session.Transaction; }
        }
        public virtual void Begin()
        {
            if (!this.Session.Transaction.IsActive)
            {
                this.isTransactionCreated = true;
                this.Session.BeginTransaction();
            }
        }
        public virtual void Commit()
        {
            this.isScopeCompleted = true;
            if (this.isTransactionCreated)
            {
                this.Transaction.Commit();
            }
        }
        public virtual void Rollback()
        {
            this.isScopeCompleted = true;
            this.Transaction.Rollback();
        }
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (!this.isScopeCompleted && this.Transaction.IsActive)
                {
                    this.Rollback();
                }
                if (this.isTransactionCreated)
                {
                    this.Transaction.Dispose();
                }
            }
        }
    }
	public class UnitOfWorkRootScope : UnitOfWorkScope
    {
        public UnitOfWorkRootScope(ISessionFactory sessionFactory)
            : base(sessionFactory)
        {
        }
        public override void Begin()
        {
            ISession session = this.SessionFactory.OpenSession();
            CurrentSessionContext.Bind(session);
            base.Begin();
        }
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (disposing)
            {
                ISession session = CurrentSessionContext.Unbind(this.SessionFactory);
                session.Close();
                session.Dispose();
            }
        }
    }

Let’s revisit our Foo class, shall we?

public class Foo {
   public Foo(IUnitOfWork uow, IRepository repository) {
      this.uow = uow;
      this.repository = repository;
   }
   public void Bar() {
      using(IUnitOfWorkScope scope = this.uow.Start()) {
         var customers = this.repository.GetCustomersWithFirstNameOf("daniel");
         // modify customers, other class could att
         scope.Commit();
      }
   }
}

Nice we gained a little bit of abstraction in our business code regarding the persistency layer but we still have two dependencies in our Foo class. But do we really need the repository abstraction? NHibernate’s ISession is itself an unit of work. So why don’t we just move these few members onto the scope?

    public interface IUnitOfWorkScope : IDisposable
    {
        void Begin();
        void Commit();
        void Rollback();
	IEnumerable FindAllBy(IQuery query)
          where T : Entity;
        ...
    }

We can even move away the generic restriction which would then allow to use projections in the query too. This simplifies Foo to the following implemention (still using the extension method approach but this time on IUnitOfWorkScope).

public class Foo {
   public Foo(IUnitOfWork uow) {
      this.uow = uow;
   }
   public void Bar() {
      using(IUnitOfWorkScope scope = this.uow.Start()) {
         var customers = scope.GetCustomersWithFirstNameOf("daniel");
         // modify customers, other class could att
         scope.Commit();
      }
   }
}

Isn’t that nice? No need for repositories. Unit testable. Simple and small abstraction. All persistency related stuff in either in the query or in the unit of work implementation and only there we need tests which either go to the database or use InMemory databases. But there is still one caveat regarding testability. Can you spot it?