IMPORTANT NOTE:
I have a new blog post about Generic Repository implementation for Entity Framework. Please check it out instead of this one: Clean, Better, and Sexier Generic Repository Implementation for Entity Framework
NOTE:
Entity Framework DbContext Generic Repository Implementation Is Now On Nuget and GitHub: https://www.tugberkugurlu.com/archive/entity-framework-dbcontext-generic-repository-implementation-is-now-on-nuget-and-github
DRY: Don’t repeat yourself which is a principle of software development aimed at reducing repetition of information of all kinds, especially useful in multi-tier architectures. That’s what Wikipedia says. In my words, if you are writing the same code twice, follow these steps:
That’s what I have done for repository classes on my DAL projects. I nearly all the time use Entity Framework to reach out my database and I create repositories in order to query and manipulate data inside that database. There are some specific methods which I use for every single repository. As you can assume, those are FindBy, Add, Edit, Delete, Save. Let’s see on code what is my story here.
First approach (worst approach)
At first, long time ago, I have been creating all the single methods for each interface. For example below one is one of my repository interfaces:
I am giving the examples here with EF 4.2 but I was following this approach with EF 4 which does not contain DbContext class.
public interface IFooRepository { IQueryable<Foo> GetAll(); Foo GetSingle(int fooId); IQueryable<Foo> FindBy(Expression<Func<Foo, bool>> predicate); void Add(Foo entity); void Delete(Foo entity); void Edit(Foo entity); void Save(); }
This repo is for Foo class I have (imaginary). Let's see the implementation for Bar class.
public interface IBarRepository { IQueryable<Bar> GetAll(); Bar GetSingle(int barId); IQueryable<Bar> FindBy(Expression<Func<Bar, bool>> predicate); void Add(Bar entity); void Delete(Bar entity); void Edit(Bar entity); void Save(); }
Implementation nearly exactly the same here. Here is also an example of implementing one of these interfaces:
public class FooRepository : IFooRepository { private readonly FooBarEntities context = new FooBarEntities(); public IQueryable<Foo> GetAll() { IQueryable<Foo> query = context.Foos; return query; } public Foo GetSingle(int fooId) { var query = this.GetAll().FirstOrDefault(x => x.FooId == fooId); return query; } public void Add(Foo entity) { context.Foos.Add(entity); } public void Delete(Foo entity) { context.Foos.Remove(entity); } public void Edit(Foo entity) { context.Entry<Foo>(entity).State = System.Data.EntityState.Modified; } public void Save() { context.SaveChanges(); } }
Also imagine this implementation for BarRepository as well. Indeed, there would be probably more repository classes for your project. After playing like that for a while I decided to do something different which still sucked but better.
A better approach but still sucks
I created a generic interface which saves me a lot of keystrokes. Here how it looks like:
public interface IGenericRepository<T> where T : class { IQueryable<T> GetAll(); IQueryable<T> FindBy(Expression<Func<T, bool>> predicate); void Add(T entity); void Delete(T entity); void Edit(T entity); void Save(); }
And how I implemented in on repository interfaces:
public interface IFooRepository : IGenericRepository<Foo> { Foo GetSingle(int fooId); }
public interface IBarRepository : IGenericRepository<Bar> { Bar GetSingle(int barId); }
You can see that I only needed to implement GetSingle method here and others come with IGenericRepositoy<T> interface.
Where I implement these repository interfaces to my concrete classes, I still need to go over all the methods and create them individually. The repository class looked like as the same. So it leads me to a final solution which is the best one I can come up with so far.
Best approach
The generic interface I have created is still legitimate and usable here. In fact, I won’t touch the repository interfaces at all. What I did here first is to create an abstract class which implements IGenericReposity<T> interface but also accepts another type parameter defined in a generic declaration which is a type of DbConetxt class. Here is how it looks like:
public abstract class GenericRepository<C, T> : IGenericRepository<T> where T : class where C : DbContext, new() { private C _entities = new C(); public C Context { get { return _entities; } set { _entities = value; } } public virtual IQueryable<T> GetAll() { IQueryable<T> query = _entities.Set<T>(); return query; } public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate) { IQueryable<T> query = _entities.Set<T>().Where(predicate); return query; } public virtual void Add(T entity) { _entities.Set<T>().Add(entity); } public virtual void Delete(T entity) { _entities.Set<T>().Remove(entity); } public virtual void Edit(T entity) { _entities.Entry(entity).State = System.Data.EntityState.Modified; } public virtual void Save() { _entities.SaveChanges(); } }
This is so nice because of some factors I like:
So, when we need to implement these changes to our concrete repository classes, we will end up with following result:
public class FooRepository : GenericRepository<FooBarEntities, Foo>, IFooRepository { public Foo GetSingle(int fooId) { var query = GetAll().FirstOrDefault(x => x.FooId == fooId); return query; } }
public class BarReposiltory : GenericRepository<FooBarEntities, Bar>, IBarRepository { public Bar GetSingle(int barId) { var query = Context.Bars.FirstOrDefault(x => x.BarId == barId); return query; } }
Very nice and clean. Inside BarRepository GetSingle method, as you see I use Context property of GenericRepository<C, T> abstract class to access an instance of DbContext.
So, how the things work inside our ASP.NET MVC project? this is another story but no so complicated. I will continue right from here on my next post.
UPDATE:
Here is the next post:
How to Work With Generic Repositories on ASP.NET MVC and Unit Testing Them By Mocking