Fixing Leaky Repository Abstractions with LINQ

Posted by Andrew on April 28, 2007

One of the issues with current implementations of the Repository pattern is that ORM specific details can leak into the Repository interface. Most commonly this takes the form of concrete ORM querying machinery such as Query Objects, Expressions or custom object query languages. This weakening of the Repository abstraction is undesirable because it can make it more difficult to use our Repositories in different ways. For example using a fake repository to speed up our unit tests.

Enter LINQ. With language-level support for building expressions, we can now shore up our Repository interface in a completely abstract way. Our query expressions are simply handed off to the appropriate LINQ-provider which does the heavy-lifting for us. Even better, normal collections can be queried using LINQ and so implementing trivial in-memory fake repositories is dead easy. We used this approach on BackgroundMotion and it worked pretty well. Here’s what some of the code looks like:

// our Repository contract...
 
public interface IRepository<T>
  where T : IIdentifiable
{
  int Count();
  int Count(Expression<Func<T, bool>> expression);
 
  void Add(T entity);
  void Remove(T entity);
  void Save(T entity);
 
  T FindOne(int id);
  T FindOne(Expression<Func<T, bool>> expression);
 
  bool TryFindOne(Expression<Func<T, bool>> expression, out T entity);
 
  IList<T> FindAll();
  IList<T> FindAll(Expression<Func<T, bool>> expression);
 
  IQueryable<T> Find();
  IQueryable<T> Find(int id);
  IQueryable<T> Find(Expression<Func<T, bool>> expression);
}
 
// and this is how we used our real Repository implementation
 
Repository<Contribution>
  .Find(c => c.ApprovedById == null);
 
// or...
 
Repository<Tag>
  .Find()
  .OrderBy(t => t.Value)
  .Take(Constants.PageSize)
  .ToList();

Using this approach we were able to implement a fake Repository that used simple collections internally and just worked.

Good times. :-)

Trackbacks

Use this link to trackback from your own site.

Comments

Leave a response

  1. Colin JackNo Gravatar Fri, 22 Jun 2007 10:42:07 CDT

    Good stuff, makes me realize its time I got my head around LINQ though.

  2. NimaNo Gravatar Wed, 19 Dec 2007 08:03:56 CST

    it seems, there are different implement of Repository. in this scenario, client must know about expression.

    is this better way or I missed something ?
    CustomerRepository customerRepository = new CustomerRepository();
    customerRepository.GetCustomerByName(”name”);

  3. AndrewNo Gravatar Wed, 19 Dec 2007 15:37:33 CST

    Hi Nima,

    You’re right, in this scenario, client code does know about the query expressions. One way to avoid this would be to create a layer of strongly-typed Repositorys that sit above this generic repository. However, if you do this you will lose the expressiveness of LINQ and so will have to create overloads/specifications that handle all your scenarios including sorting/paging etc.

    Andrew.

  4. NimaNo Gravatar Sat, 22 Dec 2007 07:27:36 CST

    Dear Andrew

    Thanks so much

  5. Jesús GarzaNo Gravatar Mon, 07 Apr 2008 17:47:04 CDT

    Dear Andrew,

    Do you know if anyone documented the repository architecture or its use on a project outside of the background site? I am starting to use linq and I think the Core.dll code could speed up the development. But I don’t understand all the implications of its use, how to set it up on my code and I can’t seem to find anyone commenting on its use.

    Thanks and best regards.

  6. adminNo Gravatar Mon, 07 Apr 2008 20:22:35 CDT

    Hi Jesús,

    People are using some of the code and patterns from BackgroundMotion but I’m not sure if anyone is using the Core assembly directly. The Repository pattern is from Domain Driven Design (Evans) and is also documented on MartinFowler.com. Jimmy Nilsson also has a book about using domain driven design patterns with .NET.

    Cheers,

    Andrew.

Comments