There are so many articles, blog posts regarding Repositories
and Unit of work. But many of them are conflicting with each other. Therefore In
this article I’m going to explain simply about the Repository and Unit of Work pattern and why we need them with a sample project .
What is Repository?
By Martin Fowler (Patterns
of Enterprise Architecture Book):
Mediates between the domain and data mapping layers, acting
like an in memory collection of
domain objects.
Why We Need?
Major benefits of Repository Patterns:
1. Decouples your application from persistence framework (in this case Entity Framework)
Approximately every Two years we get new persistence framework.
First we have ADO.NET,
LINQ TO SQL,
EF V1,
nHibernate,
…
EF4,
EF 4.1(Db Context),
Now we have EF 7
If you want to have a freedom for changing persistence frame work with minimal impact of the application then you should use the repository pattern.
So In the future if you decide to change to persistence framework we can do so with minimal impact for rest of the application. Today we can use EF as repository, tomorrow we can change to stored procedure due to optimization.
2. Minimize duplicate query logic
Imagine in few different places in our application we need to get top 10 books in a given category.
Without the repository we duplicate following code over and over again in our application.
var topTenBooks =context.Items
.Where(x.some Condition)
.OrderByDesending(x. Id)
.Take(10)
In situation like this we can encapsulate that logic in repository and simply call method like getTopTenBooks () as follows.
var books=repository. getTopTenBooks ();
What is the repository in practice?
In a nutshell this is what your repository look like. It should act like a collection of object in memory.so that we should have method to add and remove object in memory,get all object and get an object per id and find object using predicate.
In a nutshell this is what your repository look like. It should act like a collection of object in memory.so that we should have method to add and remove object in memory,get all object and get an object per id and find object using predicate.
·
Add(obj)
·
Remove(obj)
·
Get(id)
·
GetAll()
·
Find(predicate)
Implementing Repository
Note that here we don’t have method
call update () and save ().Because in
collection of memory(Repository) if you want to update an object simply get
it from collection and change it. We
don’t tell to collection to update and object.
Ex: if you want to update name of the book in collection of
memory
var Book = collection.Get(1);
Book.Name=”New Name”;
Then the next question is How are we going to save these
objects to Database?
That’s when Unit Of
Work pattern comes with repository. According to Martin Fowler (Patterns of Enterprise Architecture Book):
Unit of Work maintains
a list of objects affected by a business transaction and coordinates the
writing out of changes
Sample Code:
Here I have created demo project to implement repositories and unit of work pattern,Imagine you have Author table with colom id and name.And also Book table with id ,name and authorId as a foreign key.IRepository,Repository are generic repositories and IBookrepository and BookRepository are custormize repositories.
Here I have created demo project to implement repositories and unit of work pattern,Imagine you have Author table with colom id and name.And also Book table with id ,name and authorId as a foreign key.IRepository,Repository are generic repositories and IBookrepository and BookRepository are custormize repositories.
Ø
IRepository interface like collection of the
object in memory.it has methods like below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace Demo.Core.Repositories
{
public interface IRepositories<TEntity> where TEntity : class
{
TEntity Get(int id);
IEnumerable<TEntity> GetAll();
IEnumerable<TEntity>Find(Expression<Func<TEntity, bool>>predicate);
void Add(TEntity entity);
void AddRange(IEnumerable<TEntity>entities);
void Remove(TEntity entity);
void ReomveRange(IEnumerable<TEntity>entities);
}
}
Ø
Repository class is an implement of the
IRepository interface.in side this we have generic DbContext.
using Demo.Core.Repositories;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
namespace Demo.Persistence.Repositories
{
public class Repository<TEntity>:IRepositories<TEntity> where TEntity : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
Context = context;
}
public TEntity Get(int id)
{
return Context.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return Context.Set<TEntity>().ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return Context.Set<TEntity>().Where(predicate);
}
public void Add(TEntity entity)
{
Context.Set<TEntity>().Add(entity);
}
public void AddRange(IEnumerable<TEntity>entities)
{
Context.Set<TEntity>().AddRange(entities);
}
public void Remove(TEntity entity)
{
Context.Set<TEntity>().Remove(entity);
}
public void ReomveRange(IEnumerable<TEntity>entities)
{
Context.Set<TEntity>().RemoveRange(entities);
}
}
}
Ø
IBookRepository Interface we define any
operation that not in generic. This is customize repository.
Ex: GetTopTenBooks(),GetBookwithAuthors()
using Demo.Core.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo.Core.Repositories
{
public interface IBookRepository :IRepositories<Book>
{
IEnumerable<Book> GetTopTenBooks();
IEnumerable<Book> GetBookwithAuthors();
}
}
Ø
BookRepository derives from Repository and
additionally implement IBookRepository interface.
using Demo.Core.Domain;
using Demo.Core.Repositories;
using Demo.Persistence.Repositories;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace Demo.Persistence.Repositories
{
public class BookRepository : Repository<Book>, IBookRepository
{
public BookRepository(DemoContext context)
: base(context)
{
}
IEnumerable<Book> GetTopTenBooks()
{
return DemoContext.Books.Take(10).ToList();
}
public IEnumerable<Book> GetCoursesWithAuthors()
{
return DemoContext.Books
.Include(c => c.Author)
.OrderBy(c => c.Name)
.ToList();
}
public DemoContext DemoContext
{
get { return Context as DemoContext; }
}
}
}
Implementing Unit of Work
Unit of Work is specific to our application and going to
expose various repository based on the entities we have.
Ø
IUnitOfWork:
using Demo.Core.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo.Core
{
interface IUnitOfWork :IDisposable
{
IBookRepository Courses { get; }
IAuthorRepository Authors { get; }
int Complete();
}
}
Ø
UnitOfWork:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Demo.Core;
using Demo.Core.Repositories;
using Demo.Persistence.Repositories;
namespace Demo.Persistence
{
public class UnitOfWork:IUnitOfWork
{
private readonly DemoContext _context;
public UnitOfWork(DemoContext context)
{
_context = context;
Books = new BookRepository(_context);
Authors = new AuthorRepository(_context);
}
public IBookRepository Books { get; private set; }
public IAuthorRepository Authors { get; private set; }
}
}
That’s all. We completed repository and unit of work
implementation.
So let’s try to get Top Ten books using MVC project. I won’t
explain MVC implementation step by step. That is out of the scope.In brief what
I did was first adding database using ado.net Entitiy data model (Db first) and naming context as ‘DemoContext’.Then adding BookContrller as follow.
using Demo.Core.Domain;
using Demo.Persistence;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Demo.Controllers
{
public class BookController : Controller
{
private readonly UnitOfWork _UOWork;
public BookController()
{
_UOWork = new UnitOfWork(new DemoContext());
}
//
GET: Book
public ActionResult Index()
{
var bookwitauthor= _UOWork.Books.GetBooksWithAuthors();
return View(bookwitauthor);
}
public ActionResult getTopTenBooks()
{
//GET
TOP 10 BOOKS from Book entity
var topSelling = _UOWork.Books.getTopTenBooks();
return View(topSelling);
}
}
}
Then right click on getTopTenBooks() method and add view as
follow.
@model
IEnumerable<Demo.Core.Domain.Book>
@{
ViewBag.Title = "getTopTenBooks";
}
<h2>getTopTenBooks</h2>
<p>
@Html.ActionLink("Create
New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Description)
</th>
<th>
@Html.DisplayNameFor(model => model.Author.Name)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
@Html.DisplayFor(modelItem => item.Author.Name)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
@Html.ActionLink("Details", "Details", new { id=item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
After that when you call Book controller index method it
will show book list as follow.
Really a good start machan.
ReplyDelete