DT Tech InfoDT Tech Info

      Design Patterns

      LEARN EASY
      • Home
      • Blog
      • Design Patterns
      • Design Patterns – Repository Pattern in C#

      Design Patterns – Repository Pattern in C#

      • Posted by Muthukumar Dharmar
      • Categories Design Patterns, EF Core
      • Date July 17, 2021

      In this article, we will discuss the repository pattern. Then we will have a walk-through of the step-by-step implementation of a Repository Pattern in a C# project.

      Data Access Layer

      It is good we have several ORM mappers like, Dapper, EntityFramework, etc., These libraries are doing all the heavy lifting for us and help us to communicate with the database by simply using the programming language that we know.

      Typical Usage

      In EntityFramework our DbContext class acts as a Data Access Layer.

      In the below example we are injecting the DbContext in our Controller class, by doing this we are making our business layer directly dependent on our Data Access Layer, in other words tightly coupled with the DbContext class.  Still this approach work.

      #region Constructor
      public CustomersController(DbContext context)
      {
          this.dbContext = context;
      }
      #endregion Constructor

      Disadvantages

      It’s hard to Unit Test our Controllers/Services with the dependency of DbContext, we don’t need to perform actual database operations while executing our Unit Test cases right, All we need is to test the logic inside Controller actions.

      Let’s say,  at some point, there is a decision from management to migrate the database with some latest technology. Along with this change we have to update all our Controller classes, right. this may result in some regressions.

      Decoupling with Repository Pattern

      Actually, the Repository Pattern solves the above-mentioned problem by standing as a mediator between the Consumer and the Data Access Layer.   As you all know, in any application a typical data access operation could be Create, Read, Update & Delete(CRUD), So we need to perform CRUD operation for each and every Entity of our Domain Models.

      Repeating these functions for all the entities, kind of a duplication of work. 

      We will take advantage of the C# Generics technique to reuse the logic and avoid code duplications. 

      Step1: Interface Creation

      We need to define an interface with these common operations.

      public interface IRepository<TEntity> : IRepository<TEntity, long> where TEntity: IEntityBase { }
       
      public interface IRepository<TEntity, TKey> where TEntity : IEntityBase<TKey>
      {
          TEntity GetItemById(TKey id);
       
          IQueryable<TEntity> GetEntities(Expression<Func<TEntity, bool>> filterPredicate);
       
          int Count(Expression<Func<TEntity, bool>> filterPredicate);
       
          void Add(TEntity entity);
       
          void Update(TEntity entity);
       
          void Delete(TEntity entity);
       
          void DeleteById(TKey id);
      }

      Step2: Generic Repository Class Creation

      Create a Repository base class with the actual implementation.

      public abstract class Repository<TEntity> : Repository<TEntity, long> where TEntity : EntityBase, IEntityBase
      {
          protected Repository(DbContext dbContext) : base(dbContext) { }
      }
       
      public abstract class Repository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity : EntityBase<TKey>, IEntityBase<TKey>
      {
          protected readonly DbContext dbContext;
       
          public Repository(DbContext dbContext)
          {
              this.dbContext = dbContext;
          }
       
          public virtual TEntity GetItemById(TKey id)
          {
              return this.dbContext.Set<TEntity>().Find(id);
          }
       
          public virtual IQueryable<TEntity> GetEntities(Expression<Func<TEntity, bool>> filterCriteria = null)
          {
              return filterCriteria != null 
                          ? this.dbContext.Set<TEntity>().AsNoTracking().Where(filterCriteria) 
                          : this.dbContext.Set<TEntity>().AsNoTracking(); ;
          }
       
          public virtual int Count(Expression<Func<TEntity, bool>> predicate)
          {
              return this.dbContext.Set<TEntity>().AsNoTracking().Where(predicate).Count();
          }
       
          public virtual void Add(TEntity entity)
          {
              this.dbContext.Set<TEntity>().Add(entity);
          }
       
          public virtual int SaveChanges()
          {
              return this.dbContext.SaveChanges();
          }
       
          public virtual void Update(TEntity entity)
          {
              this.dbContext.Set<TEntity>().Update(entity);
          }
       
          public virtual void Delete(TEntity entity)
          {
              this.dbContext.Set<TEntity>().Remove(entity);
          }
       
          public virtual void DeleteById(TKey id)
          {
              TEntity entity = this.GetItemById(id);
              this.dbContext.Set<TEntity>().Remove(entity);
          }
      }
      

      Step3: Actual Repository Creation

      Now we can simply inherit from our Generic Repository base class which will automatically provide all the basic CRUD operations to manipulate the data from the database.

      public class CustomerRepository : Repository<Customer>
      {
          public CustomerRepository(DbContext dbContext) : base(dbContext) { }
      }
       
      public class ProductRepository : Repository<Product>
      {
          public ProductRepository(DbContext dbContext) : base(dbContext) { }
      }

      Step4: Update the Controller

      Now inject our Repository class using the IRepository interface and update all the actions with the repository methods.

      private readonly IRepository<Customer> customerRepo;
       
      #region Constructor
      public CustomersController(IRepository<Customer> customerRepo)
      {
          this.customerRepo = customerRepo;
      }
      #endregion Constructor

      Advantages

      Now it is simple to Unit Test this controller class by making a mock object for this Repository object.

      Even if there is a decision on moving to any new technology, Still there won’t be any change in the operations of our repository class and we don’t have to make changes to our Controllers. 

      All we have to do is update our mediator. Yes, we just need to update our Generic Repository class and everything works as before.  If you notice how the Repository pattern helps to encapsulate the actual data access logic, So that the Business Layer doesn’t need to know anything about our storage layer, it could be anything like SQL, Oracle, NoSQL, FileSysem, etc.,

      Hope you have enjoyed this article 🙂

      Tag:C#, Design Pattern, Design Patterns, EFCore, Entity Framework Core, Repository Pattern

      • Share:
      author avatar
      Muthukumar Dharmar
      Over 17 yrs of experience in the IT industry. Skill Set: Angular, RxJS Reactive Programming, AspNet WebApi, WCF, WPF, Azure, etc.,

      Previous post

      CheatSheet - Asp.Net Core Razor Pages
      July 17, 2021

      Next post

      Entity Framework - Usage of Global Query Filters
      July 19, 2021

      Leave A Reply Cancel reply

      Your email address will not be published. Required fields are marked *

      Search

      Categories

      • Angular
      • Angular PWA
      • ArchiMate
      • AspNet Core – Razor
      • AspNet Core – WebApi
      • Best Practices
      • Design Patterns
      • EF Core
      • Entity Framework
      • IdentityServer4
      • RxJs for Beginners
      • Tips & Tricks
      • Uncategorized
      • Web Development
      • WPF / WPF Core

      Latest Posts

      Azure: Storage Services
      26Sep2024
      Angular Styles – Tips and Tricks
      23Dec2023
      Typescript – Tips and Tricks
      23Dec2023
      logo-eduma-the-best-lms-wordpress-theme

      webadmin@dt-tech.info

      Organization

      • Contact Us

      Links

      • Blogs
      • Gallery

      Recommend

      • Angular
      • RxJS
      • AspNet Core – Razor
      • AspNet Core – WebApi
      • AspNetCore

      Powered by DT Tech.