Introduction
You may introduce with an Object Oriented Design Principle name DRY – Don’t repeat yourself. It is more important in Multi-tier architecture. We can use generic repository pattern to implement DRY.
What is Repository Pattern?
In most of the business operation we have to perform CRUD (Create, Read, Update and Delete) operation. A repository basically works as a mediator between our business logic layer and our data access layer of the application
Benefits of Repository Pattern
- Centralizes data logic or service logic.
- Provides a substitution point for the unit tests for both business logic and data access logic
- Provides a flexible architecture
- Can adopt new change easily
- Domain driven development is easier
What is Generic Repository Pattern?
Generic Repository is a pattern by which we can use single repository for data access of all models. Generally, we used one repository for one model to access data.
Benefits of Generic Repository Pattern
- Reduce redundancy of code
- Force developer to work same pattern – Possibility of less error or no error
- Easy to maintain – Centralize data access logic
Implementation Repository Pattern with ASP.NET MVC and Entity Framework
Let’s consider a project to keep Employee Information. Here I will show CRUD operation on employee information.
Tools and Technology used
I used following tools and technology to develop the project – Implementation of generic repository
- Visual Studio 2013
- Visual C#
- ASP.NET MVC 5
- Entity Framework 6
- Razor view engine
Step 1: Create an ASP.NET MVC 5 application using Visual Studio 2013. I kept the application name “GenericRepo”.
Help: How to create first application using asp.net MVC
Step 2: Configure connection string in web.config
Step 3: Create Model – “Employee”
public class Employee { public int Id { get; set; } public string Name { get; set; } public string FatherName { get; set; } public string MotherName { get; set; } public string Designation { get; set; } public string Dept { get; set; } }
Step 4: Create a DbContext name GenericDbContext in Repository folder.
public class GenericRepoContext : DbContext { public GenericRepoContext() : base("DefaultConnection") { } public DbSetEmployees { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { } }
Step 5: Create IGenericRepository and GenericRepository in Repository folder
interface IGenericRepositorywhere T : class { IEnumerable SelectAll(); T SelectByID(object id); void Insert(T obj); void Update(T obj); void Delete(object id); void Save(); } public class GenericRepository : IGenericRepository where T : class { private GenericRepoContext db = null; private DbSet table = null; public GenericRepository() { this.db = new GenericRepoContext(); table = db.Set (); } public GenericRepository(GenericRepoContext db) { this.db = db; table = db.Set (); } public IEnumerable SelectAll() { return table.ToList(); } public T SelectByID(object id) { return table.Find(id); } public void Insert(T obj) { table.Add(obj); } public void Update(T obj) { table.Attach(obj); db.Entry(obj).State = EntityState.Modified; } public void Delete(object id) { T existing = table.Find(id); table.Remove(existing); } public void Save() { db.SaveChanges(); } }
Step 6:
Create a controller name – EmployeeController. Select template “MVC5 Controller with read/write action”
public class EmployeeController : Controller { private IGenericRepositoryrepository = null; public EmployeeController() { this.repository = new GenericRepository (); } // GET: Employee public ActionResult Index() { var employee = repository.SelectAll().ToList(); return View(employee); } // GET: Employee/Details/5 public ActionResult Details(int id) { var employee = repository.SelectByID(id); return View(employee); } // GET: Employee/Create public ActionResult Create() { return View(); } // POST: Employee/Create [HttpPost] public ActionResult Create(Employee employee) { if (ModelState.IsValid) { repository.Insert(employee); repository.Save(); return RedirectToAction("Index"); } return View(employee); } // GET: Employee/Edit/5 public ActionResult Edit(int id) { var employee = repository.SelectByID(id); return View(employee); } // POST: Employee/Edit/5 [HttpPost] public ActionResult Edit(Employee employee) { try { repository.Update(employee); repository.Save(); return RedirectToAction("Index"); } catch { return View(); } } // GET: Employee/Delete/5 public ActionResult Delete(int id) { var employee = repository.SelectByID(id); return View(employee); } // POST: Employee/Delete/5 [HttpPost] public ActionResult Delete(int id, FormCollection collection) { try { repository.Delete(id); repository.Save(); return RedirectToAction("Index"); } catch { return View(); } } }
Step 7: Create List, Edit, Delete and details page against EmployeeController.
Create a list view
Index.cshtml
@model IEnumerable@{ ViewBag.Title = "Index"; } Index
@Html.ActionLink("Create New", "Create")
@foreach (var item in Model) { @Html.DisplayNameFor(model => model.Name) @Html.DisplayNameFor(model => model.FatherName) @Html.DisplayNameFor(model => model.MotherName) @Html.DisplayNameFor(model => model.Designation) @Html.DisplayNameFor(model => model.Dept) } @Html.DisplayFor(modelItem => item.Name) @Html.DisplayFor(modelItem => item.FatherName) @Html.DisplayFor(modelItem => item.MotherName) @Html.DisplayFor(modelItem => item.Designation) @Html.DisplayFor(modelItem => item.Dept) @Html.ActionLink("Edit", "Edit", new { id=item.Id }) | @Html.ActionLink("Details", "Details", new { id=item.Id }) | @Html.ActionLink("Delete", "Delete", new { id=item.Id })
Create Edit View
Create edit view as like list view and choose edit template for that.
_CreateOrEdit.cshtml
@model GenericRepo.Models.Employee@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })@Html.LabelFor(model => model.FatherName, htmlAttributes: new { @class = "control-label col-md-2" })@Html.EditorFor(model => model.FatherName, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.FatherName, "", new { @class = "text-danger" })@Html.LabelFor(model => model.MotherName, htmlAttributes: new { @class = "control-label col-md-2" })@Html.EditorFor(model => model.MotherName, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.MotherName, "", new { @class = "text-danger" })@Html.LabelFor(model => model.Designation, htmlAttributes: new { @class = "control-label col-md-2" })@Html.EditorFor(model => model.Designation, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Designation, "", new { @class = "text-danger" })@Html.LabelFor(model => model.Dept, htmlAttributes: new { @class = "control-label col-md-2" })@Html.EditorFor(model => model.Dept, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Dept, "", new { @class = "text-danger" })
Edit.cshtml
@model GenericRepo.Models.Employee @using (Html.BeginForm()) { @Html.AntiForgeryToken()}Employee
@Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.Partial("_CreateOrEdit", Model)@Html.ActionLink("Back to List", "Index")@section Scripts { @Scripts.Render("~/bundles/jqueryval") }
Create Delete View
Create delete view as like list view and choose delete template for that.
Delete.cshtml
@model GenericRepo.Models.EmployeeAre you sure you want to delete this?
Employee
@using (Html.BeginForm()) { @Html.AntiForgeryToken()
- @Html.DisplayNameFor(model => model.Name)
- @Html.DisplayFor(model => model.Name)
- @Html.DisplayNameFor(model => model.FatherName)
- @Html.DisplayFor(model => model.FatherName)
- @Html.DisplayNameFor(model => model.MotherName)
- @Html.DisplayFor(model => model.MotherName)
- @Html.DisplayNameFor(model => model.Designation)
- @Html.DisplayFor(model => model.Designation)
- @Html.DisplayNameFor(model => model.Dept)
- @Html.DisplayFor(model => model.Dept)
| @Html.ActionLink("Back to List", "Index")}
Create Details View
Create details view as like list view and choose details template for that.
Details.cshtml
@model GenericRepo.Models.EmployeeEmployee
- @Html.DisplayNameFor(model => model.Name)
- @Html.DisplayFor(model => model.Name)
- @Html.DisplayNameFor(model => model.FatherName)
- @Html.DisplayFor(model => model.FatherName)
- @Html.DisplayNameFor(model => model.MotherName)
- @Html.DisplayFor(model => model.MotherName)
- @Html.DisplayNameFor(model => model.Designation)
- @Html.DisplayFor(model => model.Designation)
- @Html.DisplayNameFor(model => model.Dept)
- @Html.DisplayFor(model => model.Dept)
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | @Html.ActionLink("Back to List", "Index")
Step 8: Add a link “Employee” to _Layout page like below
Step 9: Write following command in package manager console
PM> Enable-Migrations -ContextTypeName GenericRepoContext
PM> Add-Migration initalcreate
PM> Update-Database -Verbose -Force
Now your project is ready. Run application and execute CRUD operation on it. Output of the application like below.
Output:
Nice article about applying Repository Pattern on ASP.NET MVC framework.
Great lean solution with no use of dependency injection plugins, thanks Mahedee
hello nice post, can you show me how to improve performance in 2 cases
1) that is only save entity fields that has been edited or changed
2) for many case in drop down list where we only need a KEY and and VALUE/NAME. So please show to also get a helper from this generic repository that only loads/read only for key value
3) how to put this in a display template
Nice article. but Disposing objects is always good habit.
Hi,
Excellent work. I read so may blogs for this type of implementation. i never seen this kind of explanation.
Can you place UNIT OF WORK with REPOSITORY Design pattern. Iam searhing for this UOW.
If you provide Videos as well that could really help us.
Thank you,
Pardha.
Nice Article