How to use Generic Repository Pattern in C#
By FoxLearn 11/27/2024 1:30:57 PM 455
When used with Entity Framework Core (EF Core), it provides a reusable and centralized data access layer, reducing boilerplate code.
What is Generic Repository Pattern?
The Generic Repository Pattern in C# centralizes and abstracts data access logic, enabling reusable, consistent, and efficient management of common operations across different entities. This reduces redundancy by consolidating CRUD operations into a single, generic repository instead of creating entity-specific repositories.
If you have a project and you realize that each repository performs similar or similar actions, if you create consecutive multiple similar repositories it will be a big waste. Instead, you only need to create one and only one repository for manipulation with all entity classes sufficient. And that is the Generic Repository Pattern.
Why Use the Generic Repository Pattern?
In projects with multiple entities, creating and maintaining separate repositories for each one can be tedious and error-prone.
- Minimize duplication of your code
- Ensure the coder uses the same pattern
- Easy for maintenance and testing
- Minimize possible errors
The Generic Repository Pattern simplifies data access by providing reusable CRUD operations. This article demonstrates how to implement this pattern using a Department
entity and integrates it with a controller in an ASP.NET Core MVC application.
Here’s a step-by-step guide to implementing the Generic Repository Pattern in C# with Entity Framework.
We start by creating a BaseEntity
class that contains common attributes for all entities.
public class BaseEntity { public int Id { get; set; } public DateTime CreatedDate { get; set; } public DateTime ModifiedDate { get; set; } }
The BaseEntity
class contains common properties shared by all entities, such as Id
, CreatedDate
, and ModifiedDate
.
The Department
class inherits from BaseEntity
and includes a specific attribute: DepartmentName
.
public class Department : BaseEntity { public string DepartmentName { get; set; } }
Now we will proceed to create an interface called IGenericRepository. This interface will have the methods Get, GetAll, Add, Update and Delete.
// generic repository pattern c# with entity framework public interface IGenericRepository<T> where T : BaseEntity { Task<T> Get(int? id); IEnumerable<T> GetAll(); Task Add(T entity); Task Update(T entity); Task Delete(T entity); }
The IGenericRepository
interface declares the CRUD operations applicable to any entity.
Next, Create a GenericRepository class, then implement the IGenericRepository interface.
The GenericRepository
class provides the implementation of the IGenericRepository
interface using Entity Framework's DbContext
.
// generic repository pattern c# with entity framework public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity { private readonly DbContext _context; private DbSet<T> _dbset; string errorMessage = string.Empty; public GenericRepository(ApplicationDbContext context) { _context = context; _dbset = context.Set<T>(); } public async Task Add(T entity) { _dbset.Add(entity); await _context.SaveChangesAsync(); } public async Task Delete(T entity) { _dbset.Remove(entity); await _context.SaveChangesAsync(); } public async Task Update(T entity) { _dbset.Update(entity); await _context.SaveChangesAsync(); } public async Task<T> Get(int? id) { return await _dbset.SingleOrDefaultAsync(s => s.Id == id); } public IEnumerable<T> GetAll() { return _dbset.AsEnumerable(); } }
You need to create a controller named DepartmentController as shown below.
public class DepartmentController : Controller { private readonly IGenericRepository<Department> _context; public DepartmentController(IGenericRepository<Department> context) { _context = context; } // GET: Department public IActionResult Index() { return View(_context.GetAll()); } // GET: Department/Details/5 public async Task<IActionResult> Details(int? id) { if (id == null) { return NotFound(); } var department = await _context.Get(id); if (department == null) { return NotFound(); } return View(department); } // GET: Department/Create public IActionResult Create() { return View(); } // POST: Department/Create // To protect from overposting attacks, please enable the specific properties you want to bind to, for // more details see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create([Bind("Id,DepartmentName")] Department department) { if (ModelState.IsValid) { await _context.Add(department); return RedirectToAction("Index"); } return View(department); } // GET: Department/Edit/5 public async Task<IActionResult> Edit(int? id) { if (id == null) { return NotFound(); } var department = await _context.Get(id); if (department == null) { return NotFound(); } return View(department); } // POST: Department/Edit/5 // To protect from overposting attacks, please enable the specific properties you want to bind to, for // more details see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Edit(int id, [Bind("Id,CreatedDate,ModifiedDate,DepartmentName")] Department department) { if (id != department.Id) { return NotFound(); } if (ModelState.IsValid) { try { await _context.Update(department); } catch (DbUpdateConcurrencyException) { } return RedirectToAction("Index"); } return View(department); } // GET: Department/Delete/5 public async Task<IActionResult> Delete(int? id) { if (id == null) { return NotFound(); } var department = await _context.Get(id); await _context.Delete(department); if (department == null) { return NotFound(); } return View(department); } // POST: Department/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public async Task<IActionResult> DeleteConfirmed(int id) { var department = await _context.Get(id); await _context.Delete(department); return RedirectToAction("Index"); } }
The DepartmentController
uses IGenericRepository<Department>
to handle CRUD operations for the Department
entity.
Register the GenericRepository
in the Startup.cs
or Program.cs
:
services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
The Generic Repository Pattern in C# with Entity Framework is an efficient way to manage data access in applications with multiple entities. By centralizing and abstracting CRUD operations, this pattern enhances code reusability, maintainability, and scalability.