DEV Community 👩‍💻👨‍💻

Cover image for Ultimate guide for implementing Repository pattern and Unit of work for .NET core
Harshal Suthar
Harshal Suthar

Posted on • Originally published at ifourtechnolab.com

Ultimate guide for implementing Repository pattern and Unit of work for .NET core

The repository and unit of work patterns are deliberated to generate alayer between the data access layer and the business logic layer of any application. Executing these patterns can assistwrapping of your application from changes in the data store and can accelerate automated unit testing or test-driven development (TDD).

What is the Repository pattern?

The Repository pattern is used to separates the data access layer and business logic in your application. It creates the abstraction layer between data access layer and business logic layer of your application.

The repository offers a collection of an interface by providing methods to add,modify, remove, and fetch domain objects.

Assume that there is the data logic on the context which is used by the three controllers so for that you have to write the same logic three times at different places.

This problem will be solved by the repository pattern. It provides the codere-usability, maintainability, and scalability.

What is Unit of Work pattern?

When there are multiple repositories that need to be invoked or process for a single request which shares a common context for that we need to implement the Unit of Work.

We can implement the repository effectively with the help of the unit of work.

When a set of databases commit operations in that case we cannot just go and call the SaveChanges() method every time. For that, we are going tocluster the related repository into a single unit call Unit of Work.

Repository and Unit of Work pattern design

Image description

Advantages

  • Repository centralize your data logic and service logic.
  • Reduce the code, provides flexibility architecture.
  • Unit of Work provides the effective implementation of repositories. And Unit of Work is a cluster of the repositories.

Read More: 13 Important .net Core Libraries That Every .net Core Developer Should Know

Example

For example, there is a customer repository and a customer repositoryinterface.


namespace WebApplication16.Repository
{
interfaceICustomerRepo
{
//definition of your method
}
}

Enter fullscreen mode Exit fullscreen mode

This is the customer repository interface. Declare your method here and implement that method in repository.



namespace WebApplication16.Repository
{  
publicclassCustomerRepo : ICustomerRepo
{          
DbContext context;
public CustomerRepo(DbContext ctx)
{
 this.context = ctx;
}  
}
}

Enter fullscreen mode Exit fullscreen mode

This is the customer repository that implements the method from ICustomerRepo.
These repository work on their dbcontext instance that is used to perform the operations onto the database using Entity Framework Core.

So, we use the Unit of Work pattern to group the all common (CRUD) operations like create, retrieve, update, and delete and place it in the generic repository.

In IRepo, we can declare two method for add and remove as shown below.

Step 1: - Create generic repository interface


namespace WebApplication16.Repository
{
interfaceIRepowhere T : class
{
void Add(T entity);
void Delete(T entity);        
}
}

Enter fullscreen mode Exit fullscreen mode

We have defined two method Add and Delete in IRepo and implement them in Repository named Repo as shown below.

Step 2: - Create generic repository


namespace WebApplication16.Repository
{
publicclassRepo : IRepowhere T : class
{
protectedreadonly DbSet _context;
public Repo(DbContext context)
{
  _context = context.Set();
}
publicvoid Add(T entity)
{
 _context.Add(entity);
}
publicvoid Delete(T entity)
{
_context.Remove(entity);
}        
}
}

Enter fullscreen mode Exit fullscreen mode

IRepo accept the generic type reference T of class type and implement that method in repository and works on context passed on to it.

The entity set is created using context.set() method which returns the specific dbset.

Now make use of these Interface repositories to link with customer repository as shown below.

Step 3: - Create customer repository interface


namespace WebApplication16.Repository
{
interfaceICustomerRepo : IRepo
{
//declare your methods
}
}

Enter fullscreen mode Exit fullscreen mode

ICustomerRepo repository interface inherits the IRepo.

Step 4: - Create customer repository


namespace WebApplication16.Repository
{
publicclassCustomerRepo : Repo, ICustomerRepo
{
publicCustomerRepo(Context ctx) : base(ctx)       
{


}        
}
}

Enter fullscreen mode Exit fullscreen mode

Now CustomerRepo class from Repo with their type reference Customer.

We have passed the context in the constructor which is derived from the baseconstructor.

Create the Unit of Work class to group all repositories.

Step 5: - Create Unit of Work Interface


 namespace WebApplication16.Repository
{
interfaceIUoW : IDisposable
{
ICustomerRepo CustomerRepo {get;}
intCommit ();
}
}

Enter fullscreen mode Exit fullscreen mode

We can create the IUoW interface which extends the IDisposable interface that provides a mechanism for releasing unmanaged resources.

Step 6: - Create Unit of Work Class


namespace WebApplication16.Repository
{
publicclassUow : IUoW
{
privatereadonly Context _context;
private IRepo customer;
public Uow(Context context)
{
this._context = context;            
}
public ICustomerRepo CustomerRepo
{
get
{
returnnew CustomerRepo(_context);
}
}
publicint Commit()
{
return _context.SaveChanges();
}
publicvoid Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

Enter fullscreen mode Exit fullscreen mode

protectedvirtualvoid Dispose(bool disposing)
{
if (disposing)
{
 _context.Dispose();
}
}
}
}

Enter fullscreen mode Exit fullscreen mode

Unit of Work class (Uow) extends the unit of work interface (IUoW). Which has a commit method and one property.

We have passed the context in the Uow constructor that invokes the commit method in which respective operations will be saved into the database.

Now create the controller which uses the Unit of Work interface and perform the operations on database.

Planning to Hire Dedicated ASP.Net Core Developer? Your Search ends here.

Step 7: - Create Constructor


namespace WebApplication16.Controllers
{
[Route("api/[controller]")]
[ApiController]
publicclassCustomerController : ControllerBase
{
private IUoW _unitOfWork;
public CustomerController(IUoW unitOfWork)
{
_unitOfWork = unitOfWork;
}
[HttpGet]
public IEnumerable Get()
{
return _unitOfWork.CustomerRepo.GetAll();
}        
[HttpGet("{id}")]
public Customer Get(int id)
{
return _unitOfWork.CustomerRepo.GetCustomerById(id);
}
[HttpPost]
{
var customer = new Customer
{
Id = 1,FirstName = "Raj",LastName = "Patel", Age = 22
} ;            
_unitOfWork.CustomerRepo.Add(customer);
_unitOfWork.Commit();
return Ok();

}
}

Enter fullscreen mode Exit fullscreen mode

We have created the customer controller that extends controller base.

In the customer controller constructor pass the Unit of Work interface instance. Now Define your method to get, add, and delete method from the repository.

In this way, we can create the simple Unit of Work pattern for our application which helps us to improve the database transaction time.

Conclusion

In this blog, we have depicted how to implement the repository and Unit of Work pattern. Implementing both patterns can increase the testability, maintainability, and flexibility in architecture. Hope you understand it briefly.

Top comments (0)

This post blew up on DEV in 2020:

js visualized

🚀⚙️ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! 🥳

Happy coding!