Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit of Work pattern implementation

I am creating an application with ASP.NET MVC and Entity framework code first. I am using repository and unit of work pattern with influence of from following link.

http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

Here I have question about the implementation of Unit Of Work in that link unit of work is implemented via directly writing entities in class itself like.

public class UnitOfWork : IDisposable
{
    private SchoolContext context = new SchoolContext();
    private GenericRepository<Department> departmentRepository;

    public GenericRepository<Department> DepartmentRepository
    {
        get
        {

            if (this.departmentRepository == null)
            {
                this.departmentRepository = new GenericRepository<Department>(context);
            }
            return departmentRepository;
        }
    }

}

Do you think that implementation is good enough because every time I add/remove entities I need to change my Unit of work class. I believe that Unit of work should not be dependent on entities. Because in my application based on Client feedback we are going to frequently add/remove entities.

I may sound stupid but let me know your views on that.

like image 610
Jalpesh Vadgama Avatar asked Apr 16 '14 14:04

Jalpesh Vadgama


2 Answers

The Unit of Work pattern is already implemented in Entity Framework.

The DbContext is your Unit of Work. Each IDbSet is a Repository.

using (var context = new SchoolContext())   // instantiate our Unit of Work
{
    var department = context.Departments.Find(id);
}
like image 118
Ryan Langton Avatar answered Sep 30 '22 03:09

Ryan Langton


There are a few flavors of the UnitOfWorkPattern. The one you are describing is a show everything, there is a hide everything approach as well. In the hide approach the unit of work references the DbContext.SaveChanges() method and nothing else; sounds like what you want.

public YourContext : DbContext, IContext{}

public interface IUnitOfWork{
   void Commit();
}

public UnitOfWork : IUnitOfWork{
    private readonly IContext _context;

    //IOC should always inject the same instance of this, register it accordingly
    public UnitOfWork(IContext context){
        _context = context;
    }

    void Commit(){
           // try catch the validation exception if you want to return the validations this
           // way if your confident you've already validated you can put a void here or
           // return the intfrom save changes make sure you handle the disposing properly,
           // not going into that here you also may be doing other stuff here, have multiple
           // "contexts" to save in a single transaction or we have contextProcessors that
           // do stuff based on items in the context
          _context.SaveChanges();
   }
}

This leaves the issue of how you get your repositories into the classes that need them if you are not taking them from the UnitOfWork. This is best handled by an IOC framework. Again here there are a couple options. Once is to register the UnitOfWork as a single instance per request and have it injected into your custom Repository class.

public interface IRepository<T>
{
    IQueryable<T> Records();
    //other methods go here
}

public Repository : IRepository<T>
{
    private IContext _context;

    // same instance of context injected into the unit of work, this why when you Commit
    // everything will save, this can get tricky if you start adding Add, Update and stuff
    // but EF does have the support needed.
    public Repository(IContext context)
    {
       _context = context;
    }

    public Records()
    {
        return _context.Set<T>();
    }
}

public class SomeService : ISomeService{
   private readonly _myObjectRepository;

   public SomeService(IRepository<MyObject> myObjectRepository){
       _myObjectRepository = myObjectRepository;
   }
}

Personally I consider the IDbSet an sufficient abstraction so I no longer create repositories. In order to inject the IDbSets from the context though you need to register them as instances that you extract from the context in your IOC setup. This can be complex and depending on your skills you could find yourself in the situation where you have to register each IDbSet which I know you are trying to avoid.

What's nice about using the IDbSet is you have access to simple methods like Add and can avoid some of the more complex parts of working with Entity and DbEntity in a generic sense.

public class SomeService : ISomeService {
    private readonly _myObjectSet;

    // requires specialized IOC configurations because you have to pull this instance from
    // the instance of the context, personally don't know how to do this with a single
    // registration so this has the same problem as having to add each new repository to the
    // unit of work.  In this case each new Entity I add to the context requires I add an IOC
    // registration for the type.

    public SomeService(IDbSet<MyObject> myObjectSet){
        _myObjectSet= myObjectSet;
    }
}
like image 23
Honorable Chow Avatar answered Sep 30 '22 03:09

Honorable Chow