C# – Interaction between unit of work and repository patterns

cdomain-driven-designrepositoryrepository-patternunit-of-work

After reading thorugh plenty of articles I am still unsure about the responsibilities of Unit of Work pattern when interacting with repositories.

Repositories are responsible for loading and saving Aggregate root entities, so consider the following example code:

using(IUnitOfWork uow = container.CreateUnitOfWork())
{
     Repository<ARoot> roots = container.GetRepository<ARoot>();
     ARoot root = root.FindByName("ARoot");
     root.Name = "ANewName";

     roots.Save(root);
     uow.Commit();
}

The unit of work interface would be defined with the following methods:

public interface IUnitOfWork
{
     void Insert(object);
     void Update(object);        
     void Delete(object);
     void Commit();
     void Rollback();
}

Lets say the repository is implemented using a very straightforward SQL Mapper, so the FindByName contains some direct SQL to return ARoot, would the Save implementation look something like this:

public void Save(T entity)
{
      IUnitOfWork uow = GetUnitOfWork();
      // Tell the UOW we are updating this entity
      uow.Update(entity);
}

The Unit Of Work Commit code would then construct all the required SQL to map the entity back into the DB?

Question 2)

If I add an aggregate root into the Unit of work, is the unit of work responsible for persisiting the root, and its child enitities, or should be the Save method of the repository add the changed entities into the Unit Of Work? e.g

public void Save(T entity)
{
      IUnitOfWork uow = GetUnitOfWork();
      // Tell the UOW we are updating this entity
      uow.Update(entity);
      uow.Update(entity.AChildObject);
}

OR… Alternativly

Does a Unit of work only deal with aggregate roots, and when commited calls the repository Save methods for each object in its change set, keeping the SQL mapping code to persist the entity in the Repository, changing the first code example to

using(IUnitOfWork uow = container.CreateUnitOfWork())
{
     Repository<ARoot> roots = container.GetRepository<ARoot>();
     ARoot root = root.FindByName("ARoot");
     root.Name = "ANewName";

     //roots.Save(root);
     uow.Update(root);
     // and commit
     uow.Commit();
}

Thanks,

James

Best Answer

In our project we use a Repository to behave just like a collection of Entities, and the UnitOfWork is used to track the changes on those entities, and for writing them back to the data store.

If you're using LinqToSql or some other OR Mapper, then that is likely to implement a UnitOfWork pattern in itself, so often we just the ORMapper instance in our own IUnitOfWork.

Our repository interface is usually something like..

  IEnumerable<Order> FindByCustomerId(string customerId);
  void Add(Order order);
  void Remove(Order order);

We don't have any save method in the Repository. If we don't need a UnitOfWork, then the Add/Remove methods are acting directly on the datastore.

If we need a UnitOfWork, then the public interface is something like...

void Commit();
void Rollback();

The repository has an internal interface with the UnitOfWork, so when we query the repository, the returned objects are tracked by the UnitOfWork for changes. The commit method writes the changes back to the datastore, the rollback method simply clears it's changes.

When we use LinqToSql the DataContext takes care of the change tracking, on Rollback we just instantiate a new Context. Persistence is handled, across the root and its children. One UnitOfWork instance is shared between all the Repositories.

When we don't use LinqToSql, then we implement our own UnitOfWork, maybe it calls a webservice or something, in this case we do change tracking in the entity classes themselves using an EntityBase class.

We have a repository for each root, but sometimes the children of one root are used as roots themselves, so we often need something like an OrderLineRepository, because we have a Use Case in our system were the user wants to search for Order lines.