Using Both Generic and Non-Generic Repository Pattern in c#

Using Both Generic and Non-Generic Repository Pattern in c#

In this article, I am going to discuss how to implement both generic and non-generic repository pattern in ASP.NET MVC application using Entity Framework. In most of the real-time application, the generic repository contains the methods which are common for all the entities. But if you want some specific operation for some specific repository. Then you need to create a specific repository with the required operations. Here, in this article, I will show you how to implement both generic and specific repository for an entity.

As we already discussed the repository pattern is used to create an abstraction layer between the data access layer and business logic layer to perform the CRUD operations against the underlying database. We also discussed that the repository design pattern can be implemented in the following two ways. So, I strongly recommended you to read the following two articles before proceeding to this article.

  1. Non-Generic Repository
  2. Generic Repository
Generic Repository Pattern

The generic repository pattern is used to define common database operations such as Create, Retrieve Update, Delete, etc. for all the database entities in a single class.

Non-Generic Repository Pattern (Specific Repository)

The non-generic repository pattern is used to define all database operations related to a specific entity within a separate class. For example, if you have two entities let’s say, Employee and Customer, then each entity will have its own implementation repository.

So, before implementing both generic and specific repositories let us first understand the implementation guidelines. That means when to use Generic and when to use Specific and when to use both generic and specific in an application.

Repository Pattern Implementation Guidelines

If you will use one of the above implementations, then with the generic repository, you cannot use specific operation for an entity and in case of non-generic implementation, you have to write code for common CRUD operations for each entity. So better way is, just create a generic repository for commonly used CRUD operation and for specific operation create a non-generic repository and inherit from the generic repository. The below diagram explains the above things.

Using Both Generic and Non-Generic Repository Pattern in c#

Let’s understand this with one example.

We are going to work with the same example that we started in the Non-Generic Repository Design pattern, and Continue in Generic Repository Design Pattern articles. So please read these two articles before proceeding to this article.

Modify the IGenericRepository.cs file as shown below.

namespace RepositoryUsingEFinMVC.GenericRepository
{
    public interface IGenericRepository<T> where T : class
    {
        IEnumerable<T> GetAll();
        T GetById(object id);
        void Insert(T obj);
        void Update(T obj);
        void Delete(object id);
        void Save();
    }
}

Modify the GenericRepository.cs file as shown below

namespace RepositoryUsingEFinMVC.GenericRepository
{
    public class GenericRepository<T> : IGenericRepository<T> where T : class
    {
        public EmployeeDBContext _context = null;
        public DbSet<T> table = null;

        public GenericRepository()
        {
            this._context = new EmployeeDBContext();
            table = _context.Set<T>();
        }

        public GenericRepository(EmployeeDBContext _context)
        {
            this._context = _context;
            table = _context.Set<T>();
        }

        public IEnumerable<T> GetAll()
        {
            return table.ToList();
        }

        public T GetById(object id)
        {
            return table.Find(id);
        }

        public void Insert(T obj)
        {
            table.Add(obj);
        }

        public void Update(T obj)
        {
            table.Attach(obj);
            _context.Entry(obj).State = EntityState.Modified;
        }

        public void Delete(object id)
        {
            T existing = table.Find(id);
            table.Remove(existing);
        }

        public void Save()
        {
            _context.SaveChanges();
        }
    }
}

Note: The above code is the implementation of the Generic Repository where we implement the code for common CRUD operation for each entity.

Now we need to provide a specific implementation for each entity. Let say we want two extra operations for Employee entity such as to get Employees By gender and get employees by department. As these two operations are specific to Employee entity there is no point to add these two operations in the Generic Repository.

So we need to create a non-generic repository called EmployeeRepository which will also inherit from GenericRepository. Within this repository, we need to provide the two specific operations as shown below.

Modify the IEmployeeRepository.cs file as shown below.
using RepositoryUsingEFinMVC.DAL;
using RepositoryUsingEFinMVC.GenericRepository;
using System.Collections.Generic;
namespace RepositoryUsingEFinMVC.Repository
{
    public interface IEmployeeRepository : IGenericRepository<Employee>
    {
        IEnumerable<Employee> GetEmployeesByGender(string Gender);
        IEnumerable<Employee> GetEmployeesByDepartment(string Dept);
    }
}

Modify the EmployeeRepository.cs file as shown below

namespace RepositoryUsingEFinMVC.Repository
{
    public class EmployeeRepository : GenericRepository<Employee>, IEmployeeRepository
    {
        public IEnumerable<Employee> GetEmployeesByGender(string Gender)
        {
            return _context.Employees.Where(emp => emp.Gender == Gender).ToList();
        }

        public IEnumerable<Employee> GetEmployeesByDepartment(string Dept)
        {
            return _context.Employees.Where(emp => emp.Dept == Dept).ToList();
        }
    }
}

Now we need to use both these generic and non-generic repository in Employee Controller.

Modify the Employee Controller as shown below.
using RepositoryUsingEFinMVC.Repository;
using System.Web.Mvc;
using RepositoryUsingEFinMVC.DAL;
using RepositoryUsingEFinMVC.GenericRepository;

namespace RepositoryUsingEFinMVC.Controllers
{
    public class EmployeeController : Controller
    {
        private IGenericRepository<Employee> repository = null;    
        private IEmployeeRepository employee_repository = null;

        public EmployeeController()
        {
            this.employee_repository = new EmployeeRepository();
            this.repository = new GenericRepository<Employee>();
        }

        public EmployeeController(EmployeeRepository repository)
        {
            this.employee_repository = repository;
        }
        public EmployeeController(IGenericRepository<Employee> repository)
        {
            this.repository = repository;
        }


        [HttpGet]
        public ActionResult Index()
        {
            //you can not access the below two mwthods using generic repository
            //var model = repository.GetEmployeesByDepartment("IT");
            var model = employee_repository.GetEmployeesByGender("Male");
            return View(model);
        }

        [HttpGet]
        public ActionResult AddEmployee()
        {
            return View();
        }

        [HttpPost]
        public ActionResult AddEmployee(Employee model)
        {
            if (ModelState.IsValid)
            {
                repository.Insert(model);
                repository.Save();
                return RedirectToAction("Index", "Employee");
            }
            return View();
        }

        [HttpGet]
        public ActionResult EditEmployee(int EmployeeId)
        {
            Employee model = repository.GetById(EmployeeId);
            return View(model);
        }

        [HttpPost]
        public ActionResult EditEmployee(Employee model)
        {
            if (ModelState.IsValid)
            {
                repository.Update(model);
                repository.Save();
                return RedirectToAction("Index", "Employee");
            }
            else
            {
                return View(model);
            }
        }

        [HttpGet]
        public ActionResult DeleteEmployee(int EmployeeId)
        {
            Employee model = repository.GetById(EmployeeId);
            return View(model);
        }

        [HttpPost]
        public ActionResult Delete(int EmployeeID)
        {
            repository.Delete(EmployeeID);
            repository.Save();
            return RedirectToAction("Index", "Employee");
        }
    }
}

Note: Using a specific repository we can access all the operations. But using generic repository we can access only the operations which are defined in the generic repository.

Now run the application and see everything is working as expected. In the next article, I am going to discuss how to use the Unit of Work using both generic and non-generic repository in ASP.NET MVC application. Here, in this article, I try to explain how to implement both generic and non-generic repository in ASP.NET MVC application using Entity Framework step by step with a simple example. 

Leave a Reply

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