Home > Castle Project, DDD, ORM, Patterns, Yoot > Domain-Driven Design with Linq & ORM – Part 2

Domain-Driven Design with Linq & ORM – Part 2

In my last post about DDD & Linq (1.5 month ago … oops), I showed the following piece of code:

ServiceLocator.Register<IUnitOfWorkFactory, NHibernateUnitOfWorkFactory>();

using (UnitOfWork.Start())
{
    ITransaction tx = UnitOfWork.Current.BeginTransaction(IsolationLevel.ReadCommitted);
    try
    {
        IRepository<Customer> cr = UnitOfWork.Current.GetRepository<Customer>();
        Customer customer = cr.FindOne(c => c.Id == "AROUT");
        customer.Address = "125 Hanover Sq.";
        cr.Save(customer);
        tx.Commit();
    }
    catch
    {
        if (tx != null) tx.Rollback();
    }
    finally
    {
        if (tx != null) tx.Dispose();
    }
}

After thinking about it, refactoring it 10 times, I sat down this morning and finally got it the way I wanted (don’t ask me why it took so long lol):

// Configure your favorite IoC container:
// - Register an IUnitOfWorkFactory
// - Register an IRepositoryFactory
// - Register a generic IRepository<TEntity>
//   (your container must support open generic types).
// - Configure your container to use the IRepositoryFactory
//   to create instances of the IRepository<TEntity> component
//   (your container must support factories).
// Once your IoC container is set up, configure it as the ServiceProvider
// (must implement the IServiceProvider interface or use a wrapper) for the ServiceLocator helper
ServiceLocator.ServiceProvider = container;

// Start a unit of work
using (IUnitOfWork uow = UnitOfWork.Start())
{
    // Get an instance of repository
    IRepository<Customer> cr = ServiceLocator.GetService<IRepository<Customer>>();

    // Retrieve data with a Linq query
    Customer customer = cr.FindOne(c => c.CustomerID == "AROUT");

    // Modify retrieved entity
    customer.Address = "000 Hanover Sq.";

    // Ask repository to save changes
    cr.Save(customer);

    // Mark the unit of work as complete to propagate changes to data source
    uow.Complete();
}

The re-worked IRepository<T> looks like this:

public interface IRepository<TEntity> : IDisposable where TEntity : class
{
    long Count();
    long Count(Expression<Func<TEntity, bool>> predicate);
    void Add(TEntity entity);
    void Add(IEnumerable<TEntity> entities);
    void Remove(TEntity entity);
    void Remove(IEnumerable<TEntity> entities);
    void RemoveAll();
    void RemoveAll(Expression<Func<TEntity, bool>> predicate);
    void Save(TEntity entity);
    void Save(IEnumerable<TEntity> entities);
    TEntity FindOne(Expression<Func<TEntity, bool>> predicate);
    IEnumerable<TEntity> FindAll();
    IEnumerable<TEntity> FindAll(Expression<Func<TEntity, bool>> predicate);
    IQueryable<TEntity> QueryAll();
    IQueryable<TEntity> QueryAll(Expression<Func<TEntity, bool>> predicate);
}

I think it looks better ;) I currently have UoW & Repository factories for the following ORM:

  • NHibernate
  • ActiveRecord
  • LinqToSql
  • EntityFramework

The code is still very experimental, relies a lot of Castle Project‘s libraries (some might view it as a pro, others a con …), and I unfortunately don’t have much time to work more on it. If there is any interest for it, I might drop it online in its current state (basic samples, no unit test, code analysis spitting out a lot of warnings).

Feedback is welcomed. :)

Possible Improvements:

  • For simplification purpose, I might remove the dependency to a ‘ServiceProvider‘ and instead define a simple ‘UnitOfWork.Configure‘ method where we can specify the type of the IUnitOfWorkFactory & IRepositoryFactory.
  • Should the IUnitOfWork interface expose a ‘GetRepository<TEntity>‘ method to get rid of the ugly static call to ‘ServiceLocator.GetService<IRepository<T>>‘ ?
  1. Arun Nair
    October 13th, 2008 at 13:32 | #1

    Hi,
    This looks interesting. If you can provide a copy of the source code, it will be very helpful.

    thanks,

    Arun

  2. Marcel
    May 26th, 2009 at 16:24 | #2

    Hi Steve

    Can you provide me a copy of the code too?

    Thanks in advance
    Marcel

  1. No trackbacks yet.