Generic Repository Pattern in C#

Generic Repository Pattern in C# with Examples

In this article, I am going to discuss the Generic Repository Design Pattern in C# with Examples. Please read our previous article where we discussed the Basic or Non-Generic Repository Pattern in C# with an example as we are going to work with the same example which uses ASP.NET MVC and Entity Framework. At the end of this article, you will understand the following pointers in detail.

  1. What is Generic Repository Design Pattern in c#?
  2. Why do we need Generic Repository Design Pattern?
  3. How to implement Generic Repository Design Pattern in C#?

Note: We are going to implement the Generic Repository Design Pattern using the ASP.NET MVC application with Entity Framework using C# Language. In fact, we are going to work with the same example that we worked on in our previous article. So, I strongly recommend you read our Previous Article before proceeding with this article.

Why do we need Generic Repository Design Pattern in C#?

As we already discussed, in Basic Repository or Non-Generic Repository, we need to create separate repositories for each and every entity present in our application. For example, if we have three entities such as Employee, Product, and Customer, then we need to create three repositories such as EmployeeRepository, ProductRepository, and CustomerRepository.

This is actually boring and repeating work, especially if all the repositories are going to do the same kind of work (i.e. typically database CRUD operations). And this is against the DRY (Don’t Repeat Yourself) principle as we are repeating the same code again and again in each repository. To solve the above problem, the Generic Repository Design Pattern comes into the picture. Please have a look at the below diagram for a better understanding.

Why do we need Generic Repository Pattern in C#

Creating a Generic Repository:

A Generic Repository in C# typically does at least five operations as follows

  1. Selecting all records from a table
  2. Selecting a single record based on its primary key
  3. Insert a new record into a table
  4. Update an existing record in a table
  5. Delete an existing record from a table

However, the above list is not fixed. You may have more or fewer methods in your generic repository as per your business requirements. For the simplicity of this demo, let’s assume our Generic Repository going to perform the above Five Operations. To implement a Generic Repository in C#, first, we need to create an interface let’s say IGenericRepository with the above five methods, and then we need to create a class let’s say GenericRepository which will implement the IGenericRepository interface, and provide the generic implementations for the IGenericRepository interface methods. Let us proceed and implement this step by step in our existing ASP.NET MVC Application.

Adding GenericRepository Folder.

Let us first add a folder in the root directory of the project with the name GenericRepository. To do so, right-click on the Project => Add => New Folder and then Rename the folder name as GenericRepository.

Creating Generic Repository Interface:

Next, add an Interface within the GenericRepository folder with the name IGenericRepository.cs and then copy and paste the following code into it. Here, you can see, instead of Employee, the interface is working with the T type where T is going to be a class. That T can be Employee, Product, Customer, etc. 

using System.Collections.Generic;
namespace RepositoryUsingEFinMVC.GenericRepository
{
    //Here, we are creating the IGenericRepository interface as a Generic Interface
    //Here, we are applying the Generic Constraint 
    //The constraint is, T is going to be a class
    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();
    }
}

The IGenericRepository interface is a generic interface that defines the same set of five methods that we created in the IEmployeeRepository interface of our previous article. Notice that instead of the Employee entity, now we are using T everywhere. Also, notice that GetById() and Delete() methods now accept object parameters instead of integer parameters. This is necessary because different tables may have different types of primary keys (The Customers table has a string primary key whereas the Employees table has an integer primary key).

Implementing IGenericRepository Interface

Now, we need to implement the IGenericRepository interface. To do so, add a class file with the name GenericRepository within the GenericRepository Folder and then copy and paste the following code into it. The following GenericRepository<T> class is a generic class and implements the IGenericRepository<T> interface. As the following GenericRepository class uses the generic type, T, so we can’t access a DbSet as a property of the data context object. Because we don’t know in advance what DbSet type we need to use i.e. it may be Employee, Product, Customer, etc. That is the reason why a generic DbSet variable is declared at the top that points to an appropriate DbSet based on the type of T. And then using that DbSet variable, we are doing the operations. The following code is self-explained, so please go through the comment lines for a better understanding.

using RepositoryUsingEFinMVC.DAL;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

namespace RepositoryUsingEFinMVC.GenericRepository
{
    //The following GenericRepository class Implement the IGenericRepository Interface
    //And Here T is going to be a class
    //While Creating an Instance of the GenericRepository type, we need to specify the Class Name
    //That is we need to specify the actual class name of the type T
    public class GenericRepository<T> : IGenericRepository<T> where T : class
    {
        //The following variable is going to hold the EmployeeDBContext instance
        private EmployeeDBContext _context = null;

        //The following Variable is going to hold the DbSet Entity
        private DbSet<T> table = null;

        //Using the Parameterless Constructor, 
        //we are initializing the context object and table variable
        public GenericRepository()
        {
            this._context = new EmployeeDBContext();

            //Whatever class name we specify while creating the instance of GenericRepository
            //That class name will be stored in the table variable
            table = _context.Set<T>();
        }

        //Using the Parameterized Constructor, 
        //we are initializing the context object and table variable
        public GenericRepository(EmployeeDBContext _context)
        {
            this._context = _context;
            table = _context.Set<T>();
        }

        //This method will return all the Records from the table
        public IEnumerable<T> GetAll()
        {
            return table.ToList();
        }

        //This method will return the specified record from the table
        //based on the ID which it received as an argument
        public T GetById(object id)
        {
            return table.Find(id);
        }

        //This method will Insert one object into the table
        //It will receive the object as an argument which needs to be inserted into the database
        public void Insert(T obj)
        {
            //It will mark the Entity state as Added State
            table.Add(obj);
        }

        //This method is going to update the record in the table
        //It will receive the object as an argument
        public void Update(T obj)
        {
            //First attach the object to the table
            table.Attach(obj);
            //Then set the state of the Entity as Modified
            _context.Entry(obj).State = EntityState.Modified;
        }

        //This method is going to remove the record from the table
        //It will receive the primary key value as an argument whose information needs to be removed from the table
        public void Delete(object id)
        {
            //First, fetch the record from the table
            T existing = table.Find(id);
            //This will mark the Entity State as Deleted
            table.Remove(existing);
        }

        //This method will make the changes permanent in the database
        //That means once we call Insert, Update, and Delete Methods, 
        //Then we need to call the Save method to make the changes permanent in the database
        public void Save()
        {
            _context.SaveChanges();
        }
    }
}
Modifying Employee Controller

Once the GenericRepository is ready, next we need to use that generic repository in our Employee Controller. So, modify the Employee Controller as shown below. The following Controller uses the GenericRepository to perform the CRUD Operations. Further, if you notice while creating the instance of GenericRepository, we have specified the type T as Employee. So, in this case, DbSet<T> will be replaced as DbSet<Employee> in the GenericRepository and the operations are going to be performed on the Employee table. The following code is self-explained, so please go through the comment lines for a better understanding.

using System.Web.Mvc;
using RepositoryUsingEFinMVC.DAL;
using RepositoryUsingEFinMVC.GenericRepository;
namespace RepositoryUsingEFinMVC.Controllers
{
    public class EmployeeController : Controller
    {
        //Create a variable to hold the instance of GenericRepository
        private IGenericRepository<Employee> genericRepository = null;

        //Initializing the genericRepository through a parameterless constructor
        public EmployeeController()
        {
            this.genericRepository = new GenericRepository<Employee>();
        }

        //If you want to Initialize genericRepository using Dependency Injection Container,
        //Then include the following Parameterized Constructor
        //public EmployeeController(IGenericRepository<Employee> repository)
        //{
        //    this.genericRepository = repository;
        //}

        //The following Action Method is used to return all the Employees
        [HttpGet]
        public ActionResult Index()
        {
            //Call the GetAll Method of the GenericRepository instance
            var model = genericRepository.GetAll();
            return View(model);
        }

        //The following Action Method will open the Add Employee view
        [HttpGet]
        public ActionResult AddEmployee()
        {
            return View();
        }

        //The following Action Method will be called when you click on the Submit button on the Add Employee view
        [HttpPost]
        public ActionResult AddEmployee(Employee model)
        {
            //First Check whether the Model State is Valid or not
            if (ModelState.IsValid)
            {
                //If Model State is Valid, then call the Insert method GenericRepository to make the Entity State Added
                genericRepository.Insert(model);
                //To make the changes permanent in the database, call the Save method of GenericRepository
                genericRepository.Save();
                //Once the data is saved into the database, redirect to the Index View
                return RedirectToAction("Index", "Employee");
            }

            //If the Model state is not valid, then stay on the current AddEmployee view
            return View();
        }

        //The following Action Method will open the Edit Employee view based on the EmployeeId
        [HttpGet]
        public ActionResult EditEmployee(int EmployeeId)
        {
            //First, Fetch the Employee information by calling the GetById method of GenericRepository
            Employee model = genericRepository.GetById(EmployeeId);
            //Then Pass the Employee data to the Edit view
            return View(model);
        }

        //The following Action Method will be called when you click on the Submit button on the Edit Employee view
        [HttpPost]
        public ActionResult EditEmployee(Employee model)
        {
            //First Check whether the Model State is Valid or not
            if (ModelState.IsValid)
            {
                //If Valid, then call the Update Method of GenericRepository to make the Entity State Modified
                genericRepository.Update(model);
                //To make the changes permanent in the database, call the Save method of GenericRepository
                genericRepository.Save();
                //Once the updated data is saved into the database, redirect to the Index View
                return RedirectToAction("Index", "Employee");
            }
            else
            {
                //If the Model State is invalid, then stay on the same view
                return View(model);
            }
        }

        //The following Action Method will open the Delete Employee view based on the EmployeeId
        [HttpGet]
        public ActionResult DeleteEmployee(int EmployeeId)
        {
            //First, Fetch the Employee information by calling the GetById method of GenericRepository
            Employee model = genericRepository.GetById(EmployeeId);
            //Then Pass the Employee data to the Delete view
            return View(model);
        }

        //The following Action Method will be called when you click on the Submit button on the Delete Employee view
        [HttpPost]
        public ActionResult Delete(int EmployeeID)
        {
            //Call the Delete Method of the GenericRepository to Make the Entity State Deleted 
            genericRepository.Delete(EmployeeID);
            //Then Call the Save Method to delete the entity from the database permanently
            genericRepository.Save();
            //And finally, redirect the user to the Index View
            return RedirectToAction("Index", "Employee");
        }
    }
}

As shown in the above code, the IGenericRepository variable is declared with Employee as its type. The constructor then assigns an instance of GenericRepository or some other implementation of IGenericRepository to this variable.

That’s it. We are done with our implementation. Now run the application and perform the CRUD operations which should work as expected. This article gave you an understanding of the Generic Repository Pattern in C# from the context of ASP.NET MVC and Entity Framework. 

We created Entity-Specific Repositories in our previous article and Generic Repository in this article. In the next article, I am going to discuss How to use both Generic and Non-Generic Repositories in ASP.NET MVC Applications. Here, in this article, I try to explain the Generic Repository Design Pattern in C# using ASP.NET MVC application with Entity Framework. I hope you enjoy this Generic Repository Design Pattern in C# with Examples article.

9 thoughts on “Generic Repository Pattern in C#”

  1. what if i want to add a method to a specific Model ? (i think i must create an interface and repository class for that model and write my method inside it )

  2. blank

    This is suboptimal. Remember that a controller is instantiated for every request by the ControllerFactory (which by default is the DefaultControllerFactory). Each time an HTTP request is received, your implementation is creating a new database context.

    Instead, one should instantiate one context in the controller and pass it as an argument to the GenericRepository.

  3. blank

    What happens if I don’t give a particular data in update. Like for example in personal details table, I’ll get the mail id from user and I’ll save it in first. Then later I’ll get the other personal details input from the user “This time I’ll not pass the email”. Does the value for email will be null now ?

Leave a Reply

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