Unit of Work & Repository Framework with ASP.NET MVC 5, Entity Framework 6 & Unity 3 (Quick-Start Video)

Update: 08/12/2014 – Please refer to https://genericunitofworkandrepositories.codeplex.com/documentation for latest documentation. There have been breaking changes released since this recording was published.

Update: 02/24/2014 – v3.2 released, improved API and reusable queries with the Object Query Pattern. Breaking change: Framework now ships returning all things TEntity or IEnumberable for compartmentalization, you will need to change the Repository.cs (see below, what methods signatures to change) if IQueryable is preferred over IEnumerable, IEnumerable is preferred as a best practice (http://genericunitofworkandrepositories.codeplex.com/documentation).

Update: 01/06/2014 – When viewing please configure your YouTube
player to 1080p for clear viewing of the coded demos.

https://genericunitofworkandrepositories.codeplex.com/documentation

Hope everyone had a wonderful New Years holiday, with the new year starting wanted to fulfill a high request, which was a quick start video on the Unit of Work and Repository Frameworks in ASP.NET MVC with Unity for IoC and DI.

This video will touch on the following topics:

  • Entity Framework Power Tools
  • Uow & Repo Framework
  • Generating EF Mappings and POCO’s
  • Upgrading the stack to EF 6.2
  • Basic Customer CRUD Use Case with MVC Scafolding Template w/ Async
  • Refactoring the CustomerController to use UoW & Repo Framework w/ Async
  • Why the ICustomerService Approach?
  • Why Commit Unit of Work Outside the Service vs. versa
  • Quick Examples with Eager Loading, Filter, and Sorting

Sample application download: https://skydrive.live.com/redir?resid=949A1C97C2A17906%216769
(Please enable Nuget Packages Restore at the Solution Level)

Questions and/or comments please tweet @LeLong37.

Note:

1. Although the quick start video, takes the approach of committing the unit of work outside the ICustomerService exampled, whether you choose to do this inside your services or manage this outside, there is no right or wrong, this is totally team preference.

2. Also all use cases demonstrated in the CustomerController could have been satisfied by using the UnitOfWork out of the box without the need to implement the ICustomerService, however as mentioned, this is the preferred best practice.

Using ICustomerService in CustomerController


[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "CustomerID,CompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax")] Customer customer)
{
    if (ModelState.IsValid)
    {
        customer.ObjectState = ObjectState.Modified;
        _customerService.Update(customer);
        await _unitOfWork.SaveAsync();
        return RedirectToAction("Index");
    }
    return View(customer);
}

Without ICustomerService and using IUnitOfWork out of the box in the CustomerController


[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "CustomerID,CompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax")] Customer customer)
{
    if (ModelState.IsValid)
    {
        customer.ObjectState = ObjectState.Modified;
        _unitOfWork.Repository<Customer>().Update(customer);
        await _unitOfWork.SaveAsync();
        return RedirectToAction("Index");
    }
    return View(customer);
}

In this case it is preferred that the IRepository return IEnumerable vs. IQueryable.

HAVING THE REPOSITORY RETURN ALL THINGS IEnumerable or IList is a best practice and preferred approach. Down the line, if you were to ever switch out your back-end, you won’t be bound to the requirements that the back-end implements IQueryable e.g. moving from EF to pure REST services.

Question? Why does the Repository in the framework return IQueryable?

Answer: Because most devs have been spoiled with ORM’s (e.g. nHibernate.Linq, Linq to Sql, Entity Framework) returning IQueryable and I received to many requests and complaints when the Repository layer in the Framework was returning IEnumerable or IList. Another caveat is that you can’t definitively tell what SQL queries are happening in your application by looking at the Repository layer, because you haven’t truly compartmentalized them in this layer; developers are more than able to modify the query plan before the query is actually executed.

For teams that prefer all things returned as IEnumerable from Repository layer, this would require three lines of code to be changed in the framework, here’s how:

  1. Repository.IRepositoryQuery.cs

    
    IEnumerable<TEntity> Get();
    
    
  2. Repository.RepositoryQuery.cs

    
            public IEnumerable<TEntity> Get()
            {
                return _repository.Get(_filter, _orderByQuerable, _includeProperties, _page, _pageSize);
            }
    
    
  3. Repository.Repository.cs

    
            internal IEnumerable<TEntity> Get(
                Expression<Func<TEntity, bool>> filter = null,
                Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
                List<Expression<Func<TEntity, object>>> includeProperties = null,
                int? page = null,
                int? pageSize = null)
            {
                IQueryable<TEntity> query = _dbSet;
    
                if (includeProperties != null)
                    includeProperties.ForEach(i => query = query.Include(i));
    
                if (filter != null)
                    query = query.Where(filter);
    
                if (orderBy != null)
                    query = orderBy(query);
    
                if (page != null && pageSize != null)
                    query = query
                        .Skip((page.Value - 1) * pageSize.Value)
                        .Take(pageSize.Value);
    
                return query;
            }
    
    
    

Additional references: http://blog.longle.net/2013/05/11/genericizing-the-unit-of-work-pattern-repository-pattern-with-entity-framework-in-mvc/

Sample application download: https://skydrive.live.com/redir?resid=949A1C97C2A17906%216769

CodePlex download for the framework: https://genericunitofworkandrepositories.codeplex.com/

Happy coding…! πŸ™‚