HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Unit of Work with Repository Pattern MVC 5 & EF 6

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
mvcwithrepositoryworkpatternunit

Problem

I put together a sample of how I am using the Unit of Work & Repository pattern based on my understanding. Can anyone please let me know if I am implementing this the correct way? If I am not, how can I improve it?

I have an EF model with two entities: Topic and Subtopic. The EF model is called CommonGood.

Unit of Work:

/// 
/// Implementation of a UnitOfWork class
/// 
public static class UnitOfWork
{
    /// 
    /// Gets the default context
    /// 
    /// A new instance of the default context
    public static CommonGoodEntities GetContext()
    {
        return new CommonGoodEntities();
    }
}


IGenericRepository:

```
public interface IRepository
{
///
/// Gets all entities
///
/// All entities
IEnumerable GetAll();

///
/// Gets all entities matching the predicate
///
/// The filter clause
/// All entities matching the predicate
IEnumerable GetAll(Expression> predicate);

///
/// Set based on where condition
///
/// The predicate
/// The records matching the given condition
IQueryable Where(Expression> predicate);

///
/// Finds an entity matching the predicate
///
/// The filter clause
/// An entity matching the predicate
IEnumerable Find(Expression> predicate);

///
/// Determines if there are any entities matching the predicate
///
/// The filter clause
/// True if a match was found
bool Any(Expression> predicate);

///
/// Returns the first entity that matches the predicate
///
/// The filter clause
/// An entity matching the predicate
T First(Expression> predicate);

///
/// Returns the first entity that matches the predicate else null
///
/// The filter clause
/// An entity matching the predicate else null
T FirstOrDefault(Expression> predicate);

///
/// Adds a given entity to the context
///
/// The entity to add to the context
void A

Solution

You're getting there. Here's a pattern that I've used that works really well. I don't like generic "find" and "save" methods because they tend to be really complicated in order to work with everything and I find you end up pulling your hair out when you want to do something special.

Here's the base repository class. We want concrete implementations so we throw abstract on there

public abstract class BaseRepository
{

    protected UnitOfWork _uow;

    public BaseRepository(UnitOfWork unitOfWork) {
        _uow = unitOfWork;
    }

    protected MyEntities DB {
        get { return _uow.DB; }
    }

}


Heres the Unit of work implementation. An option here is having your UnitOfWork implement IDisposable

public class UnitOfWork
{
    private MyEntities _db;

    public MyEntities DB {
        get { return _db; }
    }

    public UnitOfWork() {
        _db = new MyEntities ();     
    }

    public void SaveChanges() {
        _db.SaveChanges();
    }

}


The implementation of a repository. I generally make a repository separating different entities, but there are several logical ways of separating them. In this repository you write a method that corresponds to a requirement for something like "GetAllDocuments" or "GetPerson". You then call the entities context and work on it directly. This provides the separation of the Data Access Layer with the Business Layer.

public class MyRepository : BaseRepository
{
    public MyRepository (UnitOfWork unitOfWork)
        : base(unitOfWork)
    {
    }

    public MyObject GetObject(int objectID)
    {
        return DB.Objects.FirstOrDefault(n => n.ObjectID == ObjectID);
    }
}


A base controller holds the unit of work

public class BaseController : Controller
{
    private UnitOfWork             _uow;

    protected UnitOfWork UOW {
        get {
            if (_uow == null) {
                _uow = new UnitOfWork();
            }
            return _uow;
        }
    }
}


Instantiate the repository you want to work out of in the constructor of the controller, passing in the unit of work variable that comes from the base controller.

public class HomeController : BaseController
{
    MyRepository _myrepo;

    public HomeController()
    {
         _myrepo = new MyRepository(UOW);
    }
}


Now in any of your methods, you have access to your database through business requirements without touching EF implementation

public ActionResult Index()
{
    _myRepo.GetObject(myInt);

    return View();
}


You can use multiple repos in the same controller by simply instantiating another repo. Since the unit of work is the same they are the same context, so you can work with both at the same time.

MyRepository _myrepo;
MyOtherRepository _myOtherRepo;

public HomeController()
{
     _myrepo = new MyRepository(UOW);
     _myOtherRepo = new MyOtherRepository(UOW);
}


Because of the way controllers work, a cool consequence of all this is that your contexts are "short lived". Once your GET or POST method returns, the context is destroyed.

Code Snippets

public abstract class BaseRepository
{

    protected UnitOfWork _uow;

    public BaseRepository(UnitOfWork unitOfWork) {
        _uow = unitOfWork;
    }

    protected MyEntities DB {
        get { return _uow.DB; }
    }

}
public class UnitOfWork
{
    private MyEntities _db;

    public MyEntities DB {
        get { return _db; }
    }

    public UnitOfWork() {
        _db = new MyEntities ();     
    }

    public void SaveChanges() {
        _db.SaveChanges();
    }

}
public class MyRepository : BaseRepository
{
    public MyRepository (UnitOfWork unitOfWork)
        : base(unitOfWork)
    {
    }

    public MyObject GetObject(int objectID)
    {
        return DB.Objects.FirstOrDefault(n => n.ObjectID == ObjectID);
    }
}
public class BaseController : Controller
{
    private UnitOfWork             _uow;

    protected UnitOfWork UOW {
        get {
            if (_uow == null) {
                _uow = new UnitOfWork();
            }
            return _uow;
        }
    }
}
public class HomeController : BaseController
{
    MyRepository _myrepo;

    public HomeController()
    {
         _myrepo = new MyRepository(UOW);
    }
}

Context

StackExchange Code Review Q#33611, answer score: 6

Revisions (0)

No revisions yet.