Saturday, August 21, 2010

The fallacy of the Repository/DAO interface

In most applications you need to access a database sooner or later. So you implement a generic Repository/DAO interface on top of the ORM tool of your choice to simplify your data access code. The problem is that those interfaces are most of the time abused and don’t follow their original intent as described by Martin Fowler.

A typical implementation in .NET looks like this:

   1:  public interface IProductRepository
   2:  {
   3:     Product GetById(int id);
   4:     IEnumerable<Product> FindByDescription(string template);
   5:     IEnumerable<Product> FindByPrice(IRange<decimal> priceRange);
   6:     void Add(Product product);
   7:     void Remove(Product product);
   8:  }

As more functionality is needed, this repository keeps growing and growing. Not what you should describe as a maintainable solution. Luckily there are some solutions out there:

  1. The Query Object pattern as described by Martin Fowler. A good example of Query Object is the NHibernate ICriteria with all its classes.
  2. Another possible solution is the Specifications Pattern (by Eric Evans and Martin Fowler). Specification is again very powerful especially because easy to test. In .NET we have various implementations/interpretations based on LINQ.
  3. The last is a repository implementing IQueryable (as proposed by Fabio Maulo here).

Which one do you prefer?

1 comment:

raulg said...

I've been doing some months of prototyping and am settling on the Fablo Maulo pattern of Repository on top of IQueryable/LINQ.

But you can also use the Specification pattern on top of LINQ as well (LinqSpecs and other). So really you can do Option 3 + 2 leveraging LINQ and the NH 3.0 LINQ provider.