Introduction
Over the last year I have been developing my own application using Domain Driven Design (DDD). I am also working on products in my day job that uses DDD. In the last month, myself and my fellow developers that I work with, went on a little journey to find the right way to implement the repository pattern including queries. My fellow devs and I wanted a solution to achieve the following goals:
- A solid OO approach that was not bound to a specific technology. Meaning that we could develop this in C# or Java or what ever language.
- No leaky abstraction. For example, we are using nHibernate at the moment, but in the future we might choose to use a different Object Relational Mapper (ORM). We don’t want our Repository or Finder interface to expose Nhibernate interfaces like “ISession” or “ICriteria”.
- A repository per aggregate root.
- No code duplication
- Fully testable, driven out by our unit tests and me able to mock out the dependancies.
- Friendly to our Inversion of Control (IoC) framework (ninject, spring.net and castle Windsor etc)
- Provide a fluent interface to our repositories.
None of us are new to the Repository pattern or ways to implement query objects, so we all have ideas and existing code for tackling this. Combined we come up with this.
In my own application, my implementation used extension methods, its worked well, but because extension methods are static, i had no way of mocking them out with Rhino mocks. This was not a showstopper, but meant that when i was writing unit tests in my service layer for example i have to set up the data to satisfy the logic in the extension methods.
Throughout the rest of this post, i will be using code from my own application.
The desired result
Here is an example of how we intent to use our repositories:
ApplicationUser user = applicationUserRepository
.Find.ByLoginName(request.LoginName);
As you can see the repository has a find property on it that exposes a ByLoginName method that takes a string argument and returns a single ApplicationUser object.
Entity Implementation
The ApplicationUser is a Entity, all of my Entities inherit from a base class called EntityBase:
public abstract class EntityBase
{
private int id;
protected EntityBase() : this(0) { }
protected EntityBase(int id)
{
this.id = id;
}
public int Id
{
get { return this.id; }
}
public abstract bool IsValid();
...
}
Not much to it this, all my entities have an identity and i want all my entities to be able to state if the data they contain is valid
Repository Implementation
All of my repositories extend a base IRepository interface.
public interface IRepository<T> where T : EntityBase
{
T Get(int id);
void Save(T entity);
}
As you can see the generic type is constrained by the EntityBase type. The IRepository interface is not used directly outside of my repository layer, but is extended by the typed Repository interfaces:
public interface IApplicationUserRepository : IRepository<ApplicationUser>
{
IApplicationUserFinder Find { get; }
}
In my application, I use dependency injection so my repositories are injected using the typed interface. IApplicationUserRepository has one member being the Finder interface (more on that below).
One of my objectives was to remove duplicate code, in my effort to do this, i have an abstract class in which all my repositories inherit from.
public abstract class EntityRepository<T> : IRepository<T> where T : EntityBase
{
protected readonly IPersistanceRepository repository;
public EntityRepository(IPersistanceRepository repository)
{
this.repository = repository;
}
public virtual T Get(int id)
{
return repository.Get<T>(id);
}
public virtual void Save(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
if (entity.IsValid())
{
repository.Save(entity);
}
}
protected IQueryable<T> Query()
{
return repository.Query<T>();
}
}
This class must be supplied an instance of IPersistanceRepository. Here is the IPersistanceRepository interface
public interface IPersistanceRepository
{
T Get<T>(int id);
void Save<T>(T entity);
IQueryable<T> Query<T>();
}
A concrete implementation of the IPersistanceRepository interface is the technology / ORM specific stuff. I am using NHibernate 2.0, so my concrete implementation is called “NHibernateRepository”. By using the IPersistanceRepository interface i am keeping the specifics abstracted away inside the concrete class. I have been able to successfully swap my IPersistanceRepository instance from NHibernate to a DB4o implementation with ease and no effect to my repositories.
Finder Implementation
Like the IRepository interface is used as a base interface, i also have a base IEntityFinder interface which again is not directly used outside of my repository layer.
public interface IEntityFinder<T> where T : EntityBase
{
IQueryable<T> DataSource { set; }
}
As you can see, the interface has a DataSource property of IQueryable, the reason for this is that I am using System.Linq in my project which I will come onto later. But its purpose is to give the Finder a datasource. Now for the IApplicationUserFinder interface.
public interface IApplicationUserFinder : IEntityFinder<ApplicationUser>
{
ApplicationUser ByLoginName(string loginName);
ApplicationUser ByToken(Guid token);
}
The typed Repository
Now for my implementation of my typed Repository.
public class ApplicationUserRepository : EntityRepository<ApplicationUser>, IApplicationUserRepository
{
private readonly IApplicationUserFinder finder;
public ApplicationUserRepository(IPersistanceRepository repository, IApplicationUserFinder finder)
: base(repository)
{
this.finder = finder;
this.finder.DataSource = Query();
}
public IApplicationUserFinder Find
{
get { return finder; }
}
}
This repository derives from EntityRepository and implements IApplicationUserRepository. Its constucted with its dependencies being injected. The Finder instance has it datasource set to IQuerable<ApplicationUser>.
The typed finder
using System.Collections.Generic;
using System.Linq;
public class ApplicationUserFinder : IApplicationUserFinder
{
private IQueryable<ApplicationUser> users;
public IQueryable<ApplicationUser> DataSource
{
set { users = value; }
}
public ApplicationUser ByLoginName(string loginName)
{
if (string.IsNullOrEmpty(loginName))
{
throw new ArgumentNullException("loginName");
}
return users.Where(u => u.LoginName == loginName).FirstOrDefault();
}
public ApplicationUser ByToken(Guid token)
{
return users.Where(u => u.Token == token).FirstOrDefault();
}
}
What do we have then
We have our entity, repository and Finder created. The repository and Finder have typed interfaces, which means i can wire these up in my IoC container. My IEntityFinder interface sort of went against my goal of no leaky abstraction as its using System.Linq, but i think i can live with myself. By having my finder implement an interface i could have different concrete implementations.
My finder is returning a single instance of ApplicationUser. I could have finder methods that return Iquerable that allows for method chaining etc. Plus i have not allowed for “And”, “Or” or “Not” as that is a different topic. But i have a base to work on.
nibernate repository
To be more code complete here is a snippet of my NHibernate repository that returns the initial query. I am using nhibernate 2.0 with nhibernate.linq.
using System.Linq;
using NHibernate;
using NHibernate.Linq;
public class NHibernateRepository : IPersistanceRepository
{
private readonly ISessionLocator sessionLocator;
public NHibernateRepository(ISessionLocator sessionLocator)
{
this.sessionLocator = sessionLocator;
}
public T Get<T>(int id)
{
ISession session = sessionLocator.ActiveSession();
return session.Get(id);
}
public void Save<T>(T entity)
{
...
}
public IQueryable<T> Query<T>()
{
var qry = from t in sessionLocator.ActiveSession().Linq()
select t;
return qry.AsQueryable();
}
}
The beauty of this that the NHibernate specific code is in one place, my repositories and finders have no knowledge of nhibernate. In my finders, i am using linq for objects and lambda’s for my logic. Because i am using IQuerable, i can build up the query through my finders and the execution is deferred until i call a method like “ToList” or “First” etc. The queryProvider in nhibernate.linq builds the sql statement and hits the database once with the specific query.
Finally a big thank you to Neil Martin and Tim Escott for their involvement on this. Please read this post “Creating Fluent finders and repositories part 1 which continues from this post.
Leave a Reply