A long time ago I wrote a few posts about using "Domain Driven Design"-esque repositories using Linq to SQL ("Domain Driven Design Repositories in Linq to SQL"). I still use that general pattern with a few tweaks with extra layer of a "Unit of Work" to manage context lifetimes. I'm using this rebuild as a chance to play with Entity Framework 4 and so need to implement the appropriate interfaces all over again. The only major functionality change will be bringing in support for Entity Frameworks "Include".
I'm not going to go over the full pattern here, just the new parts for Entity Framework, the IRepository interface has changed that GetAll returns an interface IQuery which is pretty much the IQueryable interface with the Include method.
The implementations for IQuery and IRepository are as follows.
publicclassEntityRepository<T> : IRepository<T>where T : class
{
privatereadonlyObjectSet<T> objectSet;
public EntityRepository(ObjectSet<T> objectSet)
{
this.objectSet = objectSet;
}
publicIQuery<T> GetAll()
{
returnnewEntityQuery<T>(objectSet);
}
publicvoid Save(T entity)
{
if (entity ==null)
thrownewArgumentNullException("entity");
objectSet.AddObject(entity);
}
publicvoid Update(T entity)
{
if (entity ==null)
thrownewArgumentNullException("entity");
objectSet.Attach(entity);
}
publicvoid Delete(T entity)
{
if (entity ==null)
thrownewArgumentNullException("entity");
objectSet.DeleteObject(entity);
}
}
publicclassEntityQuery<T> : IQuery<T>
{
privatereadonlyObjectQuery<T> query;
public EntityQuery(ObjectQuery<T> query)
{
this.query = query;
}
publicIQuery<T> Include(string path)
{
returnnewEntityQuery<T>(query.Include(path));
}
IEnumerator<T>IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)query).GetEnumerator();
}
IEnumeratorIEnumerable.GetEnumerator()
{
return ((IEnumerable)query).GetEnumerator();
}
ExpressionIQueryable.Expression
{
get
{
return ((IQueryable)query).Expression;
}
}
TypeIQueryable.ElementType
{
get
{
return ((IQueryable)query).ElementType;
}
}
IQueryProviderIQueryable.Provider
{
get
{
return ((IQueryable)query).Provider;
}
}
}
The actual Repository that gets used by the domain layer simply delegates all it's work back to a internal repository based off the current unit of work. This is important section because it decouples the domain repository from repository doing the actual work and allows me to change the underlying data source if necessary.
publicclassRepository<T> : IRepository<T>where T : class
{
privatestaticIRepository<T> Current
{
get
{
returnUnitOfWork.Current.CreateRepository<T>();
}
}
publicvirtualIQuery<T> GetAll()
{
return Current.GetAll();
}
publicvirtualvoid Save(T entity)
{
if (entity ==null)
thrownewArgumentNullException("entity");
Current.Save(entity);
}
publicvirtualvoid Update(T entity)
{
if (entity ==null)
thrownewArgumentNullException("entity");
Current.Update(entity);
}
publicvirtualvoid Delete(T entity)
{
if (entity ==null)
thrownewArgumentNullException("entity");
Current.Delete(entity);
}
}
I'll get into the Unit of Work stuff in my next post.
I've found the specification pattern a nice way to wrap up a piece
of business rule to be reused through out the application, for instance
in our e-commerce product our promotion entity builds a specification
based of it's values. We can then use this specification to determine
whether an order is valid for the promotion or even filter lists of
orders using FindAll method on List and so on. Tim McCarthy has a great
article on building Composite Specifications at "A Composite Specification Pattern Implementation in .NET 2.0".
I
don't entirely agree with his approach here as I find the leaf
specifications he has created such as GreaterThanOrEqualToSpecification
in my opinion decrease the readability of the code. While I think it
can be argued that you can use these leaf specifications to be build up
a richer larger actual domain specification it still means that the
creation is difficult to read unless you go about building a fluent
interface for the specification (which I have done in the past). You
then end up with something like the new NUnit fluent interface.
What
I'm going to try and achieve here is a way to bring together easily
different domain specifications to create richer ones. The core class
behind this is PredicateSpecification, really this is just a utility
class that combined with C# lambda expressions gives us some
interesting possibilities.
public PredicateSpecification(Predicate<T> predicate)
{
this.predicate = predicate;
}
publicoverridebool IsSatisfiedBy(T item)
{
return predicate(item);
}
}
For something different I've
decided to use the &&, || and ! operators to create our
composite specifications, this goes along with the theme above that in
trying to increase readability we should try and use the readability we
already have, i.e: that most C# developers read x && y as "x
and y" already so lets not introduce a new concept.
The abstract
Specification class is where we're adding our new overloaded operators,
and where we use our new PredicateSpecification to combine the two
arguments.
We finished off last time with creating a Repository<T> class and
matching interface. This is a general workhorse of a class that allows
such syntax as
IRepository<Item> repository = new Repository<Item>(new InMemoryUnitOfWork);
IEnumerable<Item> outOfStock = from i in repository where i.QuantityOnHand == 0 select i;
foreach(Item item in repository) { }
What
I'd like however is to be able to encapsulate some of the more complex
queries behind specialised repositories, these repositories can can
then mocked with tools other than TypeMock and move some great
interaction based testing. We'll start by moving the out of stock query
above to an ItemRepository
publicinterface IItemRepository
{
IEnumerable<Item> GetOutOfStockItems();
}
publicclass ItemRepository : Repository<Item>, IItemRepository
{
public ItemRepository(IUnitOfWork unitOfWork) : base(unitOfWork) { }
public IEnumerable<Item> GetOutOfStockItems()
{
return outOfStock = from i inthiswhere i.QuantityOnHand == 0 select i;
}
}
The
LINQ query does look a little odd since we're querying the repository
directly, in order to make this a little more readable I add a property
IQueryable<Item> Items
{
get { returnthis; }
}
to make the LINQ query
from i in Items where i.QuantityOnHand == 0 select i;
Interestingly because IItemRepository doesn't implement
IRepository<Item> we lose externally the ability to execute LINQ
queries against it (this could be desired through). I prefer altering
it however to
in order the use of LINQ and normal repository actions throughout the
system while only refactoring complex or commonly used queries into the
repository itself.
Lately I've been working with NHibernate behind a domain driven design
style repository interface, this allows for easily testability as I can
create mock repositories using Rhino Mocks and give my services
prepackaged results for testing purposes.
This has worked out great, in combination with NHibernate Query
Generator I get some very readable code. After deciding that my next
pet project would include LINQ to SQL I wanted to achieve the same
results with regard to testability without reliance on an external
database.
From some reading around the web it looked like doing interaction style
testing on LINQ style queries would be difficult due to extension
methods being static and the like (I realise TypeMock gets around this
due to using the Profiler API rather than dynamic proxies). But at the
minimum I wanted to provide prepackaged results and the ability to
create aggregate repositories with specialised queries that could be
mocked and tested.
This really isn't persistence ignorance as our model is still
tied LINQ to SQL via the attributes, but I still achieve some
worthwhile goals even if I'm not being completely ignorant.
The two best pieces of work I could find on the subject were K. Scott Allen's "Trying Out Persistence Ignorance With LINQ" and "Being Ignorant with LINQ to SQL"
by Ian Cooper. I preferred the formers approach the best and really
this work is just wrapping up his work with some personal alterations.
LINQ queries work by a QueryProvider resolving an expression,
LINQ to SQL resolves the expression to SQL whereas something like LINQ
to Amazon resolves the same expression to a web-service call. In order
to achieve our testing goals the QueryProvider that ultimately resolves
the given expression is switched. For our in-memory repository we'll be
using a List<T> and therefore LINQ to Objects.
We begin by defining out IUnitOfWork, this will create data
sources that will represent either a table in LINQ to SQL or a
List<T> in LINQ to Objects as well as provide a life cycle for
our underlying DataContext. Our InMemoryUnitOfWork is storing it's
created data sources so that repeated creations of a data source will
always have the same underlying list to mimic the behavior of our
SqlUnitOfWork which is always using the same DataContext.
publicinterface IUnitOfWork : IDisposable
{
IDataSource<T> GetDataSource<T>() where T : class;
void SubmitChanges();
}
publicclass InMemoryUnitOfWork : IUnitOfWork
{
private Hashtable dataSources = new Hashtable();
public IDataSource<T> GetDataSource<T>() where T : class
{
if(!dataSources.ContainsKey(typeof(T)))
dataSources.Add(typeof(T), new InMemoryDataSource<T>());
return dataSources[typeof(T)] as InMemoryDataSource<T>;
}
publicvoid SubmitChanges()
{
}
publicvoid Dispose()
{
}
}
publicclass SqlUnitOfWork : IUnitOfWork
{
private DataContext context;
public SqlUnitOfWork(DataContext context)
{
if(context == null)
thrownew ArgumentNullException("context");
this.context = context;
}
public IDataSource<T> GetDataSource<T>() where T : class
{
returnnew SqlDataSource<T>(context);
}
publicvoid SubmitChanges()
{
context.SubmitChanges();
}
publicvoid Dispose()
{
context.Dispose();
}
}
Now to define our IDataSource, it inherits IQueryable<T> to allow
it to be queried using LINQ. Part of the IQueryable<T> interface
is the property Provider, each data source will route all LINQ queries
to their underlying Provider to be appropriately resolved. I've also
defined some simple Save, Update and Delete methods, I'm doing this
rather than implementing something like ITable because I want to keep
the repository simple and fairly similar to NHibernate.
publicinterface IDataSource<T> : IQueryable<T> where T : class
{
void Update(T entity);
void Update(IEnumerable<T> entities);
void Delete(T entity);
void Delete(IEnumerable<T> entities);
void Save(T entity);
void Save(IEnumerable<T> entities);
}
publicclass InMemoryDataSource<T> : IDataSource<T> where T : class
{
private List<T> dataSource;
public InMemoryDataSource()
: this(new List<T>())
{
}
public InMemoryDataSource(List<T> dataSource)
{
if(dataSource == null)
thrownew ArgumentNullException("dataSource");
this.dataSource = dataSource;
}
public IEnumerator<T> GetEnumerator()
{
return dataSource.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Type ElementType
{
get
{
return dataSource.AsQueryable<T>().ElementType;
}
}
public Expression Expression
{
get
{
return dataSource.AsQueryable<T>().Expression;
}
}
public IQueryProvider Provider
{
get
{
return dataSource.AsQueryable<T>().Provider;
}
}
publicvoid Delete(T entity)
{
dataSource.Remove(entity);
}
...
}
publicclass SqlDataSource<T> : IDataSource<T> where T : class
{
private Table<T> table;
public SqlDataSource(DataContext context)
{
if(context == null)
thrownew ArgumentNullException("context");
table = context.GetTable<T>();
}
public IEnumerator<T> GetEnumerator()
{
return table.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Type ElementType
{
get
{
return table.AsQueryable<T>().ElementType;
}
}
public Expression Expression
{
get
{
return table.AsQueryable<T>().Expression;
}
}
public IQueryProvider Provider
{
get
{
return table.AsQueryable<T>().Provider;
}
}
publicvoid Delete(T entity)
{
table.DeleteOnSubmit(entity);
}
...
}
An IRepository<T> is simply another data source but I've created
this interface anyway in order to keep everything linked up with domain
driven design concepts and for future extensions. I've now also created
a base Repository<T> class that takes a given IUnitOfWork and
then uses it's given data source for all it's operations. We can NOW
create a repository with an in memory data source, add items to it
before passing it to services under test. While in our live system use
a LINQ to SQL DataContext to send all our queries to SQL Server.
publicinterface IRepository<T> : IDataSource<T> where T : class
{
}
publicclass Repository<T> : IRepository<T> where T : class
{
private IDataSource<T> dataSource;
public Repository(IUnitOfWork unitOfWork)
{
if(unitOfWork == null)
thrownew ArgumentNullException("unitOfWork");
dataSource = unitOfWork.GetDataSource<T>();
}
publicvoid Update(T entity)
{
dataSource.Update(entity);
}
publicvoid Update(IEnumerable<T> entities)
{
dataSource.Update(entities);
}
publicvoid Delete(T entity)
{
dataSource.Delete(entity);
}
publicvoid Delete(IEnumerable<T> entities)
{
dataSource.Delete(entities);
}
publicvoid Save(T entity)
{
dataSource.Save(entity);
}
publicvoid Save(IEnumerable<T> entities)
{
dataSource.Save(entities);
}
public IEnumerator<T> GetEnumerator()
{
return dataSource.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Type ElementType
{
get
{
return dataSource.ElementType;
}
}
public Expression Expression
{
get
{
return dataSource.Expression;
}
}
public IQueryProvider Provider
{
get
{
return dataSource.Provider;
}
}
}
[Test]
publicvoid LinqQueryFromInMemoryUnitOfWork()
{
IRepository<Item> repository = new Repository<Item>(new InMemoryUnitOfWork());
repository.Save(new Item() { Name = "Item1", QuantityOnHand = 10 });
repository.Save(new Item() { Name = "Item2", QuantityOnHand = 0 });
IEnumerable<Item> outOfStockItems = from item in repository where item.QuantityOnHand == 0 select item;
CollectionAssert.AreCountEqual(1, outOfStockItems.ToList());
}
Once I get some appropriate hosting sorted out I'll post the full code and unit tests.
Next time, creating specialised aggregate repositories...
Page 1 of 11
Subscribe to my RSS feed to keep up to date with the latest in tutorials and applications.