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.