The Generic Repository In C#

Friday, 25 April 2014

The Repository pattern is a commonly used pattern, that encapsulates an applications data access logic and abstracts it away from the rest of the code. This makes the code more maintainable and increases the testability.
When implementing the repository pattern you can create a repository for each of your business objects, or you can create a generic repository which would work with any of your business objects.

Ill quickly go through the code I've used for my generic repository.

 
   public interface IGenericRepository
   {
    int SaveChanges();
    
    void Dispose();

    T Find<T>(ISingleEntityQuery<T> query) where T : class;

    IEnumerable<T> Find<T>(IEntityQuery<T> query) where T : class;

    T Add<T>(T item, bool commit) where T : class;

    void Remove<T>(T item, bool commit = false) where T : class;

    IDbSet<T> SetOf<T>() where T : class;
   }
  
The interface above defines the basic data access operations you would need for an entity, such as add and delete but also has two methods Find. The find methods both work in the same way to query the data using LINQ but one returns a single entity of type T and the other returns an enumerable collection of type T. I will explain how the find method and the EntityQuery objects work later in the post.

The code below shows how I've implemented the Generic Repository Interface.

  
   public class Repository : DbContext, IGenericRepository
   
   public IDbSet<Thing> Things { get; set;}
   
   public Repository()
   {
    Configuration.ProxyCreationEnabled = true;
    Configuration.LazyLoadingEnabled = true;
   }
   
   protected override void OnModelCreating(DbModelBuilder modelBuilder)
   {
    modelBuilder.Entity<Thing>().ToTable("Thing");
    base.OnModelCreating(modelBuilder);
   }
   
   public void Remove<T>(T item, bool commit = false) where T : class
   {
    this.Set<T>().Remove(item);
    if (commit)
    {
     SaveChanges();
    }
   }

   public T Find<T>(ISingleEntityQuery<T> query) where T : class
   {
    return query.Find(this);
   }

   public IEnumerable<T> Find<T>(IEntityQuery<T> query) where T : class
   {
    return query.Find(this);
   }

   public IDbSet<T> SetOf<T>() where T : class
   {
    return this.Set<T>();
   }

   public T Add<T>(T item, bool commit = false) where T : class
   {
    var aSet = this.Set<T>();

    aSet.Add(item);

    if (commit)
    {
     SaveChanges();
    }

    return item;
   } 
  
With this implementation, the Repository doesn't need to know what type of object it will be dealing with at creation.
The SetOf<T>() method, exposes the DBContext Set<T> method, to allow access to the DbSets.

The code below shows the ISingleEntityQuery Interface:

  
  public interface ISingleEntityQuery<T>
  {
   T Find(IGenericRepository repo);
  }
 
The find method takes in the repository and returns a single instance of type T.
This code shows one of its implementations:
  
 
  public class GetThingByIdQuery : ISingleEntityQuery<Thing>
  {
   public int ThingId { get; set; }

   public GetPostByIdQuery(int thingId)
   {
    ThingId = thingId;
   }

   public Thing Find(IGenericRepository repo)
   {
    var someThing = repo.SetOf<Thing>().FirstOrDefault(t => t.Id == ThingId);
 
    return someThing;
   }
  }
 
This class encapsulates the LINQ query used to find an object. By following this pattern we have more control over the queries that can be run. This also makes the code more maintainable as we would not have different LINQ queries scattered throughout the code.

Executing that query would look like this:
  
 
  Thing someThing = _repo.Find(new GetThingByIdQuery(1));
  
 

The Entity query class works the same way, but returns a collection instead of a single entity.