4

Intro

After having read multiple articles on how to implement a Unit of Work and keeping in mind testability (unit testing), I can see the following in some of what I have read:

  • Interfaces: IRepository, IUnitOfWork. IRepository can be (probably would be) a generic like IRepository<TEntity>.
  • There is a coupling between IRepository and IUnitOfWork. In some examples, you can see a dependency in IRepository on IUnitOfWork. You would also see, multiple IRepository properties in a concrete UnitOfWork
  • In multiple examples near the end you can see a usage example like this:

    using(var uow = new UnitOfWork()) {
    //some work here, maybe accessing member repositories in uow like:
    //var item = uow.Repository1.GetById(1);
    //item.SomeModifyingOperation();
    uow.Save();
    }
    

Questions/Observations

  • Is such a usage testable? It is obviously dependent on a concrete implementation of UnitOfWork.
  • Is such an example something that is expected to not be covered by our unit tests?
  • If it is to be tested then how would the code change? would we have the unit of work injected in the constructor like ctor(IUnitOfWork uow){this.uow = uow;} and then use it like this: this.uow.Save();?
  • If we go that path then we cannot utilize the using statement and the automatic disposing of uow. We would be doing manually something like uow.Dispose();.
  • Can we (ex: Ninject) depend on the DI container to handle the disposing for us per web request (MVC)? If yes, how do we do it (Ninject) and is it an efficient approach from a design POV?
  • Would you consider that a unit of work would give access to all repositories in the domain (if UnitOfWork was exposing repositories) and thus we only have one concrete implementation of IUnitOfWork?
  • Is it better to keep IUnitOfWork as simple as containing just a Save() method signature or have it include IRepository properties or maybe a generic method signature like IRepository GetRepository<TEntity>();?

References

Community
  • 1
  • 1
MSD
  • 151
  • 6
  • I would use `IRepository.Save` instead of `IRepository.Save()`. Save you the hassle of creating multiple repositories in case you are accessing mutliple entitites. – BatteryBackupUnit Jan 27 '14 at 06:23

1 Answers1

3

Create a IUnitOfWorkFactory that is injected via DI:

public interface IUnitOfWorkFactory
{
    IUnitOfWork Create();
}

public class UnitOfWorkFactory : IUnitOfWorkFactory
{
    public IUnitOfWork Create()
    {
        return new UnitOfWork();
    }
}

Then in your consumer you inject UnitOfWorkFactory:

public MyController(IUnitOfWorkFactory workFactory)
{
    this.workFactory = workFactory;
}

public ActionResult DoSomething()
{
    using(var uow = workFactory.Create())
    {
        //do work
    }
}

This way you get the best from both worlds. You get your objects injected - helps with testability. And you get your UOW automatically disposed when needed.

By the way, this is example from the DI book worth reading for these patterns.

EDIT: This chapter from DI book is talking about Disposable objects

trailmax
  • 34,305
  • 22
  • 140
  • 234