4

I've seen a lot about UnitOfWork and Repo Pattern on the web but still don't have a clear understanding of why and when to use -- its somewhat confusing to me.

Considering I can make my repositories testable by using DI thru the use of an IoC as suggested in this post What are best practices for managing DataContext. I'm considering passing in a context as a dependency on my repository constructor then disposing of it like so?:

public interface ICustomObjectContext : IDisposable {}
public IRepository<T> // Not sure if I need to reference IDisposable here
public IMyRepository : IRepository<MyRepository> {}

public class MyRepository : IMyRepository
{
    private readonly ICustomObjectContext _customObjectContext;

    public MyRepository(ICustomObjectContext customObjectContext)
    {
        _customObjectContext = customObjectContext;
    }

    public void Dispose()
    {
        if (_customObjectContext != null)
        {
            _customObjectContext.Dispose();
        }
    }

    ...

}

My current understanding of using UnitOfWork with Repository Pattern, is to perform an operation across multiple repositories -- this behavior seems to contradict what @Ladislav Mrnka recommends for web applications:

For web applications use single context per request. For web services use single context per call. In WinForms or WPF application use single context per form or per presenter. There can be some special requirements which will not allow to use this approach but in most situation this is enough.

See the full answer here

If I understand him correctly the DataContext should be shortlived and used on a per request or presenter basis (seen this in other posts as well). In this case it would be appropriate for the repo to perform operations against the context since the scope is limited to the component using it -- right?

My repos are registered in the IoC as transient, so I should get a new one with each request. If that's correct, then I should be getting a new context (with code above) with each request as well and then disposing of it -- that said...Why would I use the UnitOfWork Pattern with the Repository Pattern if I'm following the convention above?

Community
  • 1
  • 1
Rich
  • 1,810
  • 3
  • 25
  • 35
  • Not that much related to your question: But disposing an object inside a class which you inject as dependency into this class looks quite evil. The class is apparently not responsible to instantiate the object, hence it isn't responsible to dispose it. – Slauma Jan 02 '12 at 18:45
  • Thanks @Slauma noted at Wouter's note on this below. I'll need to fix that. – Rich Jan 02 '12 at 19:33

3 Answers3

7

As far as I understand the Unit of Work pattern doesn't necessarily cover multiple contexts. It just encapsulates a single operation or -- well -- unit of work, similar to a transaction.

Creating your context basically starts a Unit of Work; calling DbContext.SaveChanges() finishes it.

I'd even go so far as to say that in its current implementation Entity Framework's DbContext / ObjectContext resembles both the repository pattern and the unit of work pattern.

Dennis Traub
  • 46,924
  • 7
  • 81
  • 102
  • Thanks @Dennis. _DbContext/ObjectContext resemble both repo and UoW pattern._ I've seen this as I was researching UoW/Repos & Entity. So in your opinion UoW with Entity is not necessary? – Rich Jan 02 '12 at 19:37
  • @Rich I would say the pattern is necessary. This because in Domain Driven Design, you only use a repository for each aggregate root, not for each table in the database (which would happen when using the Context directly). And when using the repository, you can create more specific methods like FindOrdersForCustomer and implement them in one place. Using UoW and Repository pattern makes sure you use DRY (Don't repeat yourself) and keeps all the data access logic in one place. – Wouter de Kort Jan 02 '12 at 19:50
  • As always, this depends on your actual requirements. But I'd prefer to go with the built-in UoW in EF as long as I don't need to cross context-boundaries (wich, as you already mentioned, might indicate a design flaw anyway). – Dennis Traub Jan 02 '12 at 19:51
  • @WouterdeKort Entity Framework does already implement UoW and Repository (the latter by Martin Fowler's definition, not Eric Evan's) so implementing them again on top can make sense to encapsulate data access, but also lead to increasing complexity. – Dennis Traub Jan 02 '12 at 19:54
  • @DennisTraub Do you really want to pass your ObjectContext around and let all the developers on your team write linq queries against it? Or do you want to encapsulate all database actions in a specific layer and optimize them in one place? I've done a project without a Uow/Repository layer and when we hit some performance problems we had to change queries all over the place. And btw, why use the Entity Framework to model a Domain Model, if you don't use it as a Domain Model in DDD (http://martinfowler.com/bliki/AnemicDomainModel.html)? – Wouter de Kort Jan 02 '12 at 20:00
  • As I was researching UoW I came across a lot of DDD stuff (not my intent to use DDD). @WouterdeKort my current implementation follows repo per table and I don't have any need to cross context-boundaries. I certainly don't want to pass around my ObjectContext either, so I think using an IoC container with a properly configured component will best suite my requirements. – Rich Jan 02 '12 at 20:32
  • @DennisTraub's answer/comments along with Wout's comments make this the best answer. You guys have given me enough information now to make a better decision on this. Thanks! – Rich Jan 02 '12 at 20:34
3

I would use a simplified UoW if i wanted to push context's SaveChanges away from the repositories when they share the same instance of context across one web request.

I imagine you have sth like Save() method on your repositories that looks similiar to _customObjectContext.SaveChanges(). Now lets assume you have two methods containing business logic and using repos to persist changes in DB. For the sake of simplicity we'll call them MethodA and MethodB, both of them containing a fair amount of logic for performing some activities. MethodA is used separately in the system but also it is called by MethodB for some reason. What happens is MethodA saves changes on some repository and since we are still in the same request changes made in MethodB, before it called MethodA, will also be saved regardless of whether we want it or not. So in such case we unintentionally break the transaction inside MethodB and make the code harder to understand.

I hope i described this clear enough, it wasn't easy. Anyway other than that i cannot see why UoW would be helpful in your scenario. As Dennis Traub pointed quite correctly ObjectContext and DbContext are in fact an implementation of a UoW so you'd be probably reinventing the wheel while implementing it on your own.

dmusial
  • 1,389
  • 13
  • 13
  • Dennis' answer had was most informative. +1 for your answer -- it helped. Thanks @dmusial. – Rich Jan 02 '12 at 20:36
1

The ObjectContext/DbContext is an implementation of the UnitOfWork pattern. It encapsulates several operations and makes sure they are submitted in one transaction to the database.

The only thing you are doing is wrapping it in your own class to make sure you're not depending on a specific implementation in the rest of your code.

In your case, the problem lies in the fact that your Context shouldn't be disposed of by your Repository. The Repository is not the one that instantiates the Context, so it shouldn't dispose of it either. The UnitOfWork that encapsulates multiple repositories is responsible for creating and disposing the Context and you will call a Save method on your UnitOfWork.

Code can look like this:

using (IUnitOfWork unitOfWork = new UnitOfWork())
{
   PersonRepository personRepository = new PersonRepository(unitOfWork);
   var person = personRepository.FindById(personId);

   ProductRepository productRepository = new ProductRepository(unitOfWork);
   var product= productRepository.FindById(productId);

   p.CreateOrder(orderId, product);
   personRepository.Save();
}
Wouter de Kort
  • 36,302
  • 10
  • 78
  • 99
  • So @Wouter if I register my Context as Transient (using Castle) then I shouldn't have to worry about disposing the Context correct? – Rich Jan 02 '12 at 19:57
  • @Rich Sorry I don't use Castle but I posted a code sample how I use the UoW pattern. The using statement makes sure that the UoW disposes of the context (although we don't do a new UnitOfWork() but use DI) – Wouter de Kort Jan 02 '12 at 20:05
  • In case anyone else comes across this answer & comments. The Context should be registered with a PerWebRequest Lifestyle based on recommendations I've seen on SO. – Rich Jan 03 '12 at 17:13