I originally posted this question on www.stackoverflow.com
to get some feedback regarding the usage of Repository pattern in ASP.NET MVC 3 applications. I posited that
the Repository pattern implementation was redundant when our application used LINQ with ORMs such as Nhibernate
or Entity Framework Code First. Here I explain in depth why implementing Repository pattern is redundant in ASP.NET
MVC 3 applications that uses Nhibernate 3.0 or Entity Framework Code First.
Repository Pattern as Defined
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
Popular Implementation of this Pattern
Say we are developing a blogging application and we identify the following domain models,
public class Post
{
//Post specific properties here.
}
public class Comment
{
//Comment specific properties here.
}
//.... and other domain models.
One of the popular implementations of this pattern is as follows.
First a repository via interface is defined,
public interface IPostRepository
{
void Add(Post post);
void Update(Post post);
void Remove(Post post);
Post GetById(Guid postId);
ICollection<Post> GetByCategory(string category);
}
public interface ICommentRepository
{
void Add(Comment comment);
void Update(Comment comment);
void Remove(Comment comment);
Comment GetById(Guid commentId);
ICollection<Comment> GetByPost(Guid postId);
}
Then a concrete implementation. A possible Nhibernate implementation,
public class PostRepository : IPostRepository
{
private ISession Session {get;set;}
public PostRepository(ISession session)
{
Session = session;
}
public void Add(Post post)
{
using (var txn = Session.BeginTransaction())
{
session.Save(post);
txn.Commit();
}
}
public void Update(Post post)
{
using(var txn = session.BeginTransaction())
{
session.Update(post);
txn.Commit();
}
}
public void Remove(Post post)
{
using(var txn = Session.BeginTransaction())
{
session.Delete(post);
session.Commit();
}
}
public ICollection<Post> GetByCategory(string category)
{
return Session.Query<Post>()
.Where(post => post.Category.Name.Equals(category)).ToList();
}
public Post GetById(Guid postId)
{
return session.Get<Post>(postId);
}
}
public class CommentRepository : ICommentRepository
{
private ISession Session {get;set;}
public CommentRepository(ISession session)
{
Session = session;
}
public void Add(Comment comment)
{
using (var txn = Session.BeginTransaction())
{
session.Save(comment);
txn.Commit();
}
}
public void Update(Comment comment)
{
using(var txn = session.BeginTransaction())
{
session.Update(comment);
txn.Commit();
}
}
public void Remove(Comment comment)
{
using(var txn = Session.BeginTransaction())
{
session.Delete(comment);
session.Commit();
}
}
public ICollection<Comment> GetByPostId(Guid postId)
{
return Session.Query<Comment>()
.Where(comment => comment.PostId.Equals(postId)).ToList();
}
public Comment GetById(Guid commentId)
{
return session.Get<Comment>(commentId);
}
}
And finally we use those repositories in our corresponding Controller classes – assuming we are using a
Dependency Injection Framework to constructor-inject our dependencies – Repositories – into the Controllers.
public class PostController : Controller
{
private IPostRepository PostRepository{get;set;}
public PostController(IPostRepository postRepository)
{
PostRepository = postRepository;
}
[HttpPost]
public ActionResult Create(Post post)
{
if(ModelState.IsValid)
{
PostRepository.Add(post);
return RedirectToAction("Edit", post.Id);
}
return View(post);
}
//Rest of the CRUD controller methods
}
public class CommentController : Controller
{
private ICommentRepository CommentRepository{get;set;}
public CommentController(ICommentRepository commentRepository)
{
CommentRepository = commentRepository;
}
[HttpPost]
public ActionResult Create(Comment comment)
{
if(ModelState.IsValid)
{
CommentRepository.Add(comment);
return RedirecToAction("Edit", comment.Id);
}
return View(comment);
}
// Rest of the Comment CRUD action methods.
}
Redundancy in the Implementation of this Pattern
The Repository pattern implementation shown above doesn’t serve as a useful abstraction. This is mostly
because the actual work of providing a mapping layer and a collection like interface is done by the ORM
– NHibernate and LINQ respectively. The Repository pattern here mostly acts as a thin proxy to the actual
implementation. Since the abstraction – IRepository implementation – isn’t useful it serves more as noise rather than
a useful abstraction.
Furthermore, un-necessary code is being written without any realizable benefit – either developer productivity or product quality. Because the above pattern is prone to code bloat it also increases the possibility of defects in the software system.
Because the pattern also emphasizes repeatability – in the interface and then in the implementation – it is also prone to the side-effects of a less DRY code.
A Possible Alternative Implementation
One possible more DRY and concise alternative would be to remove the usage of interface inheritance pattern and use the facility and the API already provided for by the ORM framework. A possible alternative implementation for an ASP.NET MVC 3 application could be as follows,
public class PostController : Controller
{
private ISession Session{get;set;}
public PostController(ISession session)
{
Session = session;
}
[HttpPost]
public ActionResult Create(Post post)
{
if(ModelState.IsValid)
{
Session.Save(post);
return RedirectToAction("Edit", post.Id);
}
return View(post);
}
public ActionResult Index()
{
return View(Session.Query<Post>());
}
}
Summary
The reason for emphasizing on the conciseness of the codebase is because a concise, DRY code is less prone to defects, i.e. the more
you can write the least possible lines of code the less chances you have of introducing *defects and or bugs in your software
system.* The implementation of the Repository pattern as outlined above adds to the verbosity and code bloat of the system
without any realizable technical benefit.