开发者

Interaction between unit of work and repository patterns

Aft开发者_JS百科er 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


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.


Typically the way I like to see it done is the UoW tracks the changes which are saved by directly calling IRepository.Save().

I also prefer the UoW code to be handled as an aspect and outside of the interactions with the domain. This means it is either handled by some global command handlers or the web services code as part of completing the request. In other words beginning a request opens a unit-of-work, ending it closes it. This way the domain can be ignorant of the UoW and it's implementation.

Committing the unit of work is what then causes the changes made by calling .Save() and other change methods to be persisted. Quite possibly the UoW is what is tracking these changes somehow.


  • UnitOfWork is your transaction handler
  • Repository is doing the acutal work to load/save objects to the data store

I use definitions similar to:

IUnitOfWork { Commit(); }
IRepository { GetAll(); GetById(); Add(T item); Remove(T item); }

I wouldn't have the UnitOfWork creating SQL - that logic would be in your Repository. What data store are you using?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜