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. :-)

Dynamic Linq Queries - Contains Operator

Posted by Andrew on April 24, 2007

Ayende just posted about dynamic LINQ queries and how not to write them.

On BackgroundMotion we were using Linq to SQL and needed the Contains operator. Unfortunately, on the CTP we were using the Contains operator wasn’t implemented by the Linq to SQL provider. Happily however, we were able to emulate it by dynamically building the required query. Here is the code:

public static class LinqContainsPredicateBuilder
{
  public static Expression<Func<T, bool>> Build<T, S>(ICollection<S> collection, string targetProperty)
  {
    Invariant.ArgumentNotEmpty(collection, "collection");
    Invariant.ArgumentNotEmpty(targetProperty, "targetProperty");
 
    Expression completeExpression = null;
    ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "t");
 
    foreach (S item in collection)
    {
      Expression nextExpression = Expression.EQ
        (
        Expression.Property(parameterExpression, typeof(T).GetProperty(targetProperty)),
        Expression.Constant(item)
        );
 
      completeExpression = (completeExpression != null)
        ? Expression.OrElse(completeExpression, nextExpression)
        : nextExpression;
    }
 
    return (Expression<Func<T, bool>>)QueryExpression.Lambda(completeExpression, parameterExpression);
  }
}

For example, let’s say we are interested in finding all the Tag objects in the repository corresponding to a list of tags entered by a user. We could do this like so:

IList<string> candidateTags = new List<string>();
 
candidateTags.Add("Foo");
candidateTags.Add("Bar");
candidateTags.Add("Baz");
 
Expression<Func<T, bool>> expr
  = LinqContainsPredicateBuilder.Build<Tag, string>(candidateTags , "Value");
 
// now use the expression in a LINQ query...

This code will return any Tag objects that have a Value property matching any of the elements in the candidateTags list.

Being able to do this kind of thing is powerful and compelling feature of LINQ.

PowerShell Gadget Ranked 4th Best Gadget by IDG

Posted by Andrew on April 17, 2007

As JD would say: “Good Times!” Seriously, it’s really awesome to see people using and enjoying the gadget.

Check it out:

http://www.idg.se/2.1085/1.103990

Architecture Camp Slides & Demos

Posted by Andrew on April 15, 2007

Thanks to everyone who attended the camp. Good times were had by all :-)

Here are the slides and demos from my Enterprise Patterns & Testability talk.

PowerShell Gadget 1.3 Released

Posted by Andrew on April 12, 2007

See my dedicated PowerShell Gadget page for details.