Linq Repositories

Recently, the beta of Linq to LLBLGen Pro was announced, which adds linq-querying capabilities to LLBLGen, the Object Relational Mapper that I use in most of my projects.

LLBLGen's querying API is very powerful, but also somewhat complex. For example, to retrieve a list of orders from all customers in the Northwind database for customers in the UK, you would write something like this:

EntityCollection<OrderEntity> orders = new EntityCollection<OrderEntity>(new OrderEntityFactory());
RelationPredicateBucket bucket = new RelationPredicateBucket(CustomerFields.Country == "UK")
bucket.Relations.Add(OrderEntity.Relations.CustomerEntityUsingCustomerId)
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
	adapter.FetchEntityCollection(orders, bucket)
}

Linq support maintains the type safety, whilst also allowing this query to be expressed in a more SQL-like fashion (which I personally find to be more intuitive):

using(DataAccessAdapter adapter = new DataAccessAdapter())
{
	var meta = new LinqMetaData(adapter);
	var query = from o in meta.Order
			where o.Customer.Country == "UK"
			select o;
 
	var results = query.ToList();
}

This got me thinking...now that there are several ORMs that have linq support, wouldn't it be nice if there was a consistent method for performing linq-based queries, independent of the underlying ORM implementation. And thus the linq-repository was born.

The majority of the work is done by the BaseRepository class which acts as a wrapper around the underlying linq provider. There's also an IRepository interface which the BaseRepository implements:

public interface IRepository<T> : IQueryable<T> where T : class
{
	void Save(T toSave);
	void Save(T toSave, bool isNew);
	void Delete(T toDelete);
}
 
public abstract class BaseRepository<T> : IRepository<T> where T : class
{
	private IQueryable<T> source;
 
	protected IQueryable<T> Source
	{
		get { return source; }
		set { source = value; }
	}
 
	protected BaseRepository(IQueryable<T> source)
	{
		this.source = source;
	}
 
	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return source.GetEnumerator();
	}
 
	public IEnumerator GetEnumerator()
	{
		return source.GetEnumerator();
	}
 
	public Expression Expression
	{
		get { return source.Expression; }
	}
 
	public Type ElementType
	{
		get { return source.ElementType; }
	}
 
	public IQueryProvider Provider
	{
		get { return source.Provider; }
	}
 
	public abstract void Save(T toSave);
	public abstract void Delete(T toDelete);
	public abstract void Save(T toSave, bool isNew);

Note that the constructor for BaseRepository takes an IQueryable representing the underlying linq provider. Now, the LLBLGen-specific subclass:

public class LLBLGenRepository<T> : BaseRepository<T> where T : EntityBase2, IEntity2, new()
{
	public IDataAccessAdapter Adapter { get; private set; }
 
	public LLBLGenRepository(IDataAccessAdapter adapter, IElementCreator2 elementCreator)
			: base(CreateQuery(adapter, elementCreator))
	{
		this.Adapter = adapter;
	}
 
	private static IQueryable CreateQuery(IDataAccessAdapter adapter, IElementCreator2 elementCreator)
	{
		return new DataSource2(adapter, elementCreator, functionMappings, null);
	}
 
	public override void Save(T toSave)
	{
		if (toSave == null)
			throw new ArgumentNullException("toSave");
 
		Adapter.SaveEntity(toSave);
	}
 
	public override void Save(T toSave, bool isNew)
	{
		if (toSave == null)
			throw new ArgumentNullException("toSave");
 
		if (isNew) toSave.IsNew = true;
 
		Adapter.SaveEntity(toSave);
	}
 
	public override void Delete(T toDelete)
	{
		Adapter.DeleteEntity(entity);
	}

Note that the constructor for the LLBLGenRepository takes instances of an IDataAccessAdapter and an IElementCreator (the two objects necessary for running linq-queries against LLBLGen) and creates a DataSource2 object (the LLBLGen query provider) which is then passed to the BaseRepository's constructor.

So, I can now write code like this:

IRepository<OrderEntity> orders = new LLBLGenRepository<OrderEntity>(new DataAccessAdapter(), new ElementCreator());
 
var query = from o in orders
		where o.Customer.Country == "UK"
		select o;

To remove the calls to new DataAccessAdapter() and new ElementCreator(), I moved the responsibility for instantiating the repository over to an IoC container:

//in my application startup routine:
IoC.Initialise(new WindsorContainer());
IoC.Container.AddComponent<IDataAccessAdapter, DataAccessAdapter>();
IoC.Container.AddComponent<IElementCreator2, ElementCreator>();
IoC.Container.AddComponent("Repository", typeof(IRepository<>), typeof(LLBLGenRepository<>));

The IoC static class is simply a wrapper for the Windsor container.

Now I can instantiate repositories like this:

IRepository<OrderEntity> orders = IoC.Resolve<IRepository<OrderEntity>>();

I don't really like this, so I wrap it in a static gateway:

public static class Repository
{
	public static IRepository<T&t; For<T>() where T : class, new()
	{
		return IoC.Resolve<IRepository<T>>();
	}
}

...and now I can write queries like this:

var query = from o in Repository.For<OrderEntity>
		where o.Customer.Country == "UK"
		select o;

Alternatively, now that the repository is registered with Windsor, I can inject the repository directly into my ASPNET MVC Controllers:

public class OrdersController : ConventionController
{
	private IRepository<OrderEntity> ordersRepository;
 
	public OrdersController(IRepository<OrderEntity> repository)
	{
		this.ordersRepository = repository;
	}
 
	public void OrdersFromCustomersInTheUk()
	{
		ViewData["orders"] = from o in ordersRepository
						where o.Customer.Country == "UK"
						select o;
	}
}
Written on March 24, 2008