Hey there! So, I really like Generic Repositories. They are a very useful design pattern and are enjoyable to use once configured properly. However, when I first started learning about this design pattern I found a lot of the tutorials out there to be overly convoluted. The goal of this article is to get you up and running with a simple but powerful Generic Repository.
This tutorial assumes general working knowledge of Entity Framework and is based around MVC, though it could be applied to other frameworks and patterns.
As a side note or disclaimer, most of the code shown here is actually slightly modified code from the open source NopCommerce ecommerce platform. I think NopCommerce has a great implementation of a generic repository, so why rewrite the whole thing? The whole point of this in the first place is to avoid rewriting code. Don’t worry if you don’t even know what NopCommerce is – the code here is stand alone and has no dependency on the platform. I have simply extracted some of it out and simplified it for a tutorial.
Let’s quickly review the purpose and benefits of a Generic Repository.
A Generic Repository allows us to use one class to manage all of the database operations for our domain entities. This is hugely useful, because it means we don’t have to rewrite the create, read, update and delete operations for each of our entities. Instead, we can reuse the same class over and over. Generic Repositories also include the benefit of any repository layer – they provide an abstraction level over our data access, so we could add in more logic or customization between our consuming layers and the database. They also make sure our application stays loosely coupled – we could swap out our data access layer and as long as it adheres to the Repository contracts, things can still work.
At a high level, generic Repositories are implemented by using Type parameters and interfaces, which allows the Repository to remain agnostic to specific classes as long as the type passed in adheres to the contract of the interface. If we make sure the interface contains all the methods and properties we’ll need inside our repository, we can operate on any class that implements it.
Another benefit of Generic Repositories is that they work well with Dependency Injection. This means in our MVC controller or other classes, we can ask for a repository of any type, and our DI Container should be able to provide that for us. Understanding DI isn’t crucial for this post. At the end of the post I will show you how to use your Generic Repository with or without Dependency Injection. First off, let’s take a look at building a generic repository!
Step 1: Domain Models and Mapping Classes
First we just need to create some entities. These will be mapped to database tables and represent your business objects. In our scenario we are just going to use a simple example of authors and blog posts. Make sure these classes inherit from a class called BaseEntity. In our case BaseEntity doesn’t really do much, but we are going to use it as sort of a filter or marker when we search for classes to use in our repository. Below you can see two domain classes and the BaseEntity class.
public class Author : BaseEntity { public virtual int Id { get; set; } public virtual string Name { get; set; } }
public class BlogPost : BaseEntity { public virtual int Id { get; set; } public virtual string Title { get; set; } public virtual string Body { get; set; } }
public class BaseEntity { }
Next we need to create mapping classes for these entities. These classes provide additional meta data that tells Entity Framework how to map our domain objects to the database. By abstracting the mappings out into separate classes we gain greater flexibility, which we’ll see in a moment. These mapping classes use Entity Framework’s fluent API, which I am a big fan of.
public partial class AuthorMap : EntityTypeConfiguration<Author> { public AuthorMap() { this.ToTable("Author"); this.HasKey(bp => bp.Id); this.Property(bp => bp.Name).IsRequired(); } }
public partial class BlogPostMap : EntityTypeConfiguration<BlogPost> { public BlogPostMap() { this.ToTable("BlogPost"); this.HasKey(bp => bp.Id); this.Property(bp => bp.Title).IsRequired(); this.Property(bp => bp.Body).IsRequired(); } }
Step 2: DbContext and IDbContext
Next we need a DbContext, which handles the lower level database operations for our entities. This part might look complicated at first glance but don’t panic! Read it carefully and you’ll see it’s really simple.
The first method is the Set method. This method is basically just a helper that allows us to call the Set method of the DbContext base class. The set method accepts a type parameter, which means we will be able to return a set of whatever type the Repository asks for. Notice we’re using the New keyword to hide the parent implementation. This allows us to have a method with the same name and still call the parent implementation of the method.
Inside this class we also want to override the OnModelCreating method. It’s pretty common in Entity Framework to override this method. Inside of the method we have two choices, manually register each of our entity types, or have our context class find them for us and register all of them for us. I have included examples of both in the code below – the manual way is just commented out. The dynamic way just searches the current assembly and finds any classes that inherit from the BaseEntity class we used with our models.
public class SampleContext : DbContext, IDbContext { public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity { return base.Set<TEntity>(); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //DYNAMIC WAY OF MAPPING OUR ENTITIES var typesToRegister = Assembly.GetExecutingAssembly().GetTypes() .Where(type => !String.IsNullOrEmpty(type.Namespace)) .Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in typesToRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(configurationInstance); } //MANUAL WAY OF MAPPING OUR ENTITIES //modelBuilder.Configurations.Add(new AuthorMap()); //modelBuilder.Configurations.Add(new BlogPostMap()); base.OnModelCreating(modelBuilder); } }
We also want to add an interface called IDbContext. The main purpose of this interface is simple – in our main Generic Repository class we want to be able to refer to our context class using an interface rather than a class. This way we can pass in different context classes without having to tightly couple our Repository and Context classes. To make all of this happen, we just have to make sure the interface defines the methods we need. Now any context class we pass in that fulfills the interface contract will work with our repository. The SaveChanges method is actually defined on DbContext, so we don’t need to implement it in our own context class. We are just adding SaveChanges into the interface contract so that we can access the method inside our Repository, where we only refer to the context through the interface. The code for this is really simple.
public interface IDbContext { IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity; int SaveChanges(); }
Step 3: GenericRepository and IRepository
The next class is the most important – the Repository class! This is the class that will serve as an abstraction over our database operations.
First lets define an interface for our repository. We want to use an interface again to keep our components loosely coupled. This will allow us to change out our repository layer later down the road if we want to – as long as it adheres to the interface contract it will still work. Another benefit of using this approach is that you could have multiple repositories at once. If you are using dependency injection, you could conditionally bind different repositories for different controllers…this topic is beyond the scope of this post but just know that it allows for more options.
public interface IRepository<T> { void Insert(T entity); void Update(T entity); void Delete(T entity); }
Next we need our Repository implementation class. Let’s just call the class GenericRepository and make sure that it implements our interface. We also want to add a property called Entities, which uses the Set method of our context class we defined earlier. Remember, the Set method allows us to map the Entities property to any type as long as it inherits from BaseEntity – this is the heart of our entire Generic Repository.
We can add another property called Table that just returns the Entities. The rest of our methods are the ones defined by our interface and just perform our standard create, update, and delete operations.
public class GenericRepository<T> : IRepository<T> where T : BaseEntity { private readonly IDbContext _context; private IDbSet<T> _entities; public GenericRepository(IDbContext context) { this._context = context; } protected virtual IDbSet<T> Entities { get { if (_entities == null) _entities = _context.Set<T>(); return _entities; } } public virtual IQueryable<T> Table { get { return this.Entities; } } public virtual void Insert(T entity) { if (entity == null) throw new ArgumentNullException("entity"); this.Entities.Add(entity); this._context.SaveChanges(); } public virtual void Update(T entity) { if (entity == null) throw new ArgumentNullException("entity"); this._context.SaveChanges(); } public virtual void Delete(T entity) { if (entity == null) throw new ArgumentNullException("entity"); this.Entities.Add(entity); this._context.SaveChanges(); } }
Bonus: Setting Up Dependency Inection and Using our Repository
This article doesn’t cover DI in depth, but if you’re already familiar with the design pattern, here is how you would hook up a Generic Repository with DI. I’m going to use Ninject for this example because it’s awesome.
If you install Ninject through Nuget it will add a NinjectWebCommon class to your project. Inside this class, we want to pay attention to the RegisterServices method at the bottom. Modify it so that it looks like the code below. Now whenever we ask for a repository of a certain type, Ninject will supply that for us. You can also see an example of how we can use this inside our controllers using constructor injection.
private static void RegisterServices(IKernel kernel) { kernel.Bind<IDbContext>().To<SampleContext>().InRequestScope(); kernel.Bind(typeof(IRepository<>)).To(typeof(GenericRepository<>)).InRequestScope(); }
public class HomeController : Controller { private IRepository<BlogPost> _blogPostRepo; private IRepository<Author> _authorRepo; public HomeController(IRepository<Author> authorRepo, IRepository<BlogPost> blogPostRepo) { _blogPostRepo = blogPostRepo; _authorRepo = authorRepo; } public ActionResult Index() { //YOU CAN MANUALLY INSTANTIATE THE REPOSITORIES IF NOT USING DEPENDENCY INJECTINO //var context = new SampleContext(); //var _authorRepo = new GenericRepository<Author>(context); //var _blogPostREpo = new GenericRepository<BlogPost>(context); _authorRepo.Insert(new Author() { Name = "Bob" }); _blogPostRepo.Insert(new BlogPost() { Title = "Story", Body = "Blah" }); return View(); } }