In the past few weeks I have revisited the specification pattern using Linq. I have teased it, toyed with it and tricked it up. And today I announce the public availability of a project demonstrating my current thoughts. You can grab the solution from Google Code at http://code.google.com/p/linq-specifications.
I have no doubt that improvements can and will be made if this generates any wider adoption. For now, it suits what I am currently working on quite nicely. YMMV.
Below is a class diagram of the current core of the project. Use it as a quick reference but be sure to check out the code for a more in-depth view.
Shortly I will do up a few examples on the project wiki that will flesh out some of the gotchas I have come across already and I need some more testing around some of the elements. For now, however, I just wanted to get this out in the wild. Feel free to comment/flame. I look forward to any feedback.
In the previous to parts to this series (here and here) I showed the basic infrastructure framework for using Linq-based specifications with a flexible repository interface. In this article I dig deeper into the Expression based find functionality and it's implementation.
The Goal
Specification based query support on the repository is a great feature for encapsulation of any query logic. My major problem with this approach was the creation of trivial specifications on a per-domain-object basis. This would litter the code with specifications that had very little functionality contained within them. Generally this is not a bad thing but, in this instance, for the sake of maintainabilty and simplicity I wanted a to be able to perform ad-hoc queries.
The solution was to make my repository able to accept queries like :
var repository = new Repository<Person>(session);
var people = repository
.FindAll(p => p.Name == "steve");
The AdHoc specification
Since I have already made the decision that my MatchingCriteria are of type Expression, the AdHoc specification is trivial - but very cool. The implementation looks like :
public class AdHoc<T> : Specification<T> where T : IEntity
{
private readonly Expression<Func<T, bool>> expression;
public AdHoc(Expression<Func<T, bool>> expression)
{
this.expression = expression;
}
public override Expression<Func<T, bool>> MatchingCriteria
{
get { return expression; }
}
}
Simplifying the repository using the AdHoc specification
By utilising this simple but powerful specification class we can simplify the api to our IRepository. We are now able to add a FindOne and FindAll overload that accept Linq based queries in an AdHoc fashion. The implementation is as simple as :
public IQueryable<T> FindAll(Expression<Func<T, bool>> expression)
{
return FindAll(new AdHoc<T>(expression));
}
This functionality is able to be consumed in the following fashion (satisfying our goal for this task) :
var people = repository.FindAll(p => p.Name == "steve");
Conclusion
In combination with the flexibility built into the IRepository interface we now have a basis for a data access layer with maximum flexibility. Sql queries are created at execution time to reflect the criteria that we have applied through domain specifications - be they concrete or ad-hoc.
In Part 1 of this series I expressed my goal of a powerful Linq implementation for the specifications within my domain. In this part of the series I go into further detail and show I have implemented my repositories to support the pattern.
The IRepository definition
In the code below I have restricted my IRepository to be read-only for the purposes of the exercise. Obviously in reality there would be more functionality defined on this interface.
The use of the specification as a parameter to the Find methods is obvious. The use of an Expression is not so obvious at this stage and I will elaborate on this functionality later in the series.
public interface IRepository<T> where T : IEntity
{
T FindOne(Guid id);
T FindOne(Expression<Func<T, bool>> expression);
T FindOne(Specification<T> specification);
IQueryable<T> FindAll();
IQueryable<T> FindAll(Expression<Func<T, bool>> expression);
IQueryable<T> FindAll(Specification<T> specification);
}
The Repository
Implementing the repository means tying oneself to a particular Linq provider. In my case I chose Linq to NHibernate but switching it out for another implementation should be trivial.
See in the repository implementation that work is able to be integrated with the specifications by calling either SatisfyElementFrom (FindOne) of SatisfyElementsFrom (FindAll) and providing a candidate parameter provided by the Linq provider - in this case Linq to NHibernate provides a Queryable list proxy when we specify session.Linq().
public class Repository<T> : IRepository<T> where T : IEntity
{
private readonly ISession session;
public Repository(ISession session)
{
this.session = session;
}
public T FindOne(Guid id)
{
return session.Get<T>(id);
}
public T FindOne(Expression<Func<T, bool>> expression)
{
return FindOne(new AdHoc<T>(expression));
}
public T FindOne(Specification<T> specification)
{
return specification.SatisfyingElementFrom(session.Linq<T>());
}
public IQueryable<T> FindAll()
{
return (from t in session.Linq<T>() select t);
}
public IQueryable<T> FindAll(Expression<Func<T, bool>> expression)
{
return FindAll(new AdHoc<T>(expression));
}
public IQueryable<T> FindAll(Specification<T> specification)
{
return specification.SatisfyingElementsFrom(session.Linq<T>());
}
}
Conclusion
In this article I have shown an implementation of my repository facilitated by the use of Linq to NHibernate. The most striking part is the simplicity of the code. We have nicely seperated out our query concerns and the repository provides us with flexibility and also efficiency thanks to the power of Linq.
Disclaimer : I am unsure if what I am about to show here is a bridge too far in terms of bastardising the specification pattern ... it very well may be the case. However, Linq has provided a new paradigm that needs to be embraced, and sometimes that requires the tweaking of existing pratices and patterns.
Background Info
For some background on this article I recommend reading the following primers. I would never have to got to where I did without them. Please check out:
Implementing the Specification Pattern via Linq
[http://ubik.com.au/article/named/implementing_the_specification_pattern_with_linq]
Linq, the Specification Pattern and Encapsulation
[http://www.iridescence.no/post/Linq-the-Specification-Pattern-and-Encapsulation.aspx]
Implementing ORM-independent Linq queries
[http://rabdullin.com/implementing-orm-independent-linq-queries/]
The Goal
I wanted a flexible way to leverage the deferred execution power of Linq in my application. The logical place for this to occur was deep in the data access layer at the repository level. Also, as always, I wanted the ability to encapsulate my query logic into specifications and this became the real integration challenge with linq.
Specifications are easy to apply to existing in-memory collections - they fit that paradigm well. But at the lower level I knew linq could provide more power than what was previously possible with the traditional specification pattern. I wanted a way to leverage the deffered execution of Linq to drive my specifications for querying.
The Specification Class
My specification class is not dependent on any particular Linq to SQL provider. I chose to use Linq to NHibernate but that was a personal choice. I am quite sure that a switch to Linq-To-SQL would result in no modifications to any existing specifications. This provider agnostic specification implementation is a nice example of what a common language paradigm like Linq can provide.
Notice that the base abstract specification class handles all of the matching work for the specification. Any inheriting specification simply needs to specify their relevant MatchingCriteria. The SatisfyingElementFrom method (singular) simply enforces that a single result is returned. The bulk of the work is done in SatisfyingElementsFrom, which actually applies the criteria. Note that it is critical that the Matching criteria is of type Expression. This ensures we have access to the expression parsing power of Linq. Simply using a Func or a Predicate will break this implementation.
public abstract class Specification<T> where T : IEntity
{
public abstract Expression<Func<T, bool>> MatchingCriteria { get; }
public T SatisfyingElementFrom(IQueryable<T> candidates)
{
return SatisfyingElementsFrom(candidates).Single();
}
public IQueryable<T> SatisfyingElementsFrom(IQueryable<T> candidates)
{
return candidates.Where(MatchingCriteria).AsQueryable();
}
}
A simple specification
Below is the code for a simple specification implementation. Notice how it has no responsibility apart from specifying the criteria that it represents.
public class PersonById : Specification<Person>
{
private readonly Guid id;
public PersonById(Guid id)
{
this.id = id;
}
public override Expression<Func<Person, bool>> MatchingCriteria
{
get { return p => p.Id == id; }
}
}
Conclusion
So far I have demonstrated how to implement specification classes that have the potential to harness the power of Linq. Please follow the other parts of the series to see further implementation details - specifically the repository.