What is the Repository Pattern?
- Non-generic and Generic Repository Pattern
- What is the Unit of Work (UoW)?
- Benefits of UoW
- How to implement the unit of work with repository pattern in ASP.NET Core Web API
1. What is the Repository Pattern?
The repository pattern creates the abstraction layer between database access and business logic. In that case, Instead of writing the entire data access logic on the controller, it's better to write it in a different class called a repository.
2. Non-Generic and Generic Repository Pattern
Non-Generic Repository Pattern
All database actions related to a given entity are defined using the non-generic repository pattern within a separate class. For Example, suppose we have two entities (Ex-Student and Employee ). In that case, we will create two repositories for each entity with the basic CRUD operations and other operations related to each entity.
Generic Repository Pattern
The generic repository pattern is used to provide common database operations for all database entities in a single class, such as CRUD operations and so on. First, I'll show how to implement the generic repository pattern with the Example.
3. What is the Unit of Work (UoW)?
The Unit of Work is a type of business transaction, and it will aggregate all Repository transactions (CRUD) into a single transaction. Only one commit will be made for all modifications. If any transaction fails to assure data integrity, it will be rolled back. Because it does not block any data table until it commits the modifications, the Unit of Work is commonly referred to as a lazy evaluation transaction.
The above code example seems to be fine. But the issue will arise when we add another repository for another entity like this repository. For Example, if we add the repository for the Customer entity, we have to maintain its instance of DbContext. Then these repositories will maintain their instance of DbContext. This could lead to problems if each DbContext has its in-memory list of updates to entity records. In this situation, if one repository's SaveChanges fails while the other succeeds, database inconsistency will arise. This is where the UnitOfWork concept comes into play.
High level of UoW and Repository Pattern
Also, You can see the high-level view of the Unit of Work and Repository pattern in the above figure.
4. Benefits of Unit Of Work (UoW)
- Reduce the Duplicate queries and codes
- Could increase the loosely couple with DI in the application
- Easy to do unit testing or test-driven development (TDD)
- Increase the abstraction level and maintain the business logic separately.
5. How to implement the unit of work with repository pattern in ASP.NET Core Web API
First, we need to create an ASP.NET Core Web API project. I am not explaining how to create it here. Then run it and check the project.
Then we need to install the required packages for use to SQL server and entity framework core. In that case, you could navigate to Nuget package manager and then install the required packages into our solution.
Then remove the boilerplate code that has been created when creating the project (WeatherForecast.cs, Controller/WeatherForecastController.cs) after we need to modify the appsettings.json file to add the connection string of our database. So, It's a small task, and it's up to you.
In here, I follow the code-first approach in EF core to create and manage our database. In that case, we need to create a Model (Entity) class. So, first, create the folder called Models in the root directory and then create the Employee model class inside the Model folder as below code.
Employee.cs
Then we need to create DbContext for our application. In that case, Create a folder called Data in the root directory and then create DBContext class which implement the DbContext as below code and also need to our Employee model class into DbContext as below code.
DBContext.cs
You can see the DbContext class with the above code. In that code, the OnModelCreating method provides the ability for us to manage the table properties of the tables in the database. As well, we add our Employee model class. In that case, the DbSet property will help to create the table which adds with it by using the EF Core.
Then we have to create our database. In that case, navigate to the package manager console of visual studio and then use the following commands to create the database. First, enter the add-migration to create the migration by adding the migration snapshot and then enter update-database to create and update the database by using the last migration snapshot.
Now we created our database with our ASP.NET Core Web API project.
Now we have to implement the repository pattern. In that case, I follow the generic repository pattern to create the repository pattern for our project. First, we need to create a folder called services in the root directory and then create the IGenericRepository interface inside the service folder as the following code.
IGenericRepository.cs
I explained the Generic repository above. Here, T is a specific class, and the functions will depend on our requirements and preference. In this case, I added 6 functions that are commonly used on other repositories.
Now implement this IGenericRepository. Create a new class called GenericRepository, which implements IGenericRepository inside the services folder as following code.
GenericRepository.cs
This class will implement the IGenericRepository Interface. The DBContext also will be injected here. In this approach, all operations connected to the dbContext object are hidden within Repository Classes. However, we have not yet committed/updated/saved the database modifications in any way. This is something that should not be done in a Repository Class. We'll discuss that with the Unit of Work.
Now we have to create an interface called IEmployeeRepository.
IEmployeeRepository.cs
Here, We need to inherit IGenericRepository and add the new functions related to IEmployeeRepository. For Example, we could add the functions called GetEmployeeAttendance() because it's not a common operation that is not suitable for the IGenericRepository.
Now we have to implement this IEmployeeRepository. Create a class called UserRepository inside the services folder as the following code.
EmployeeRepository.cs
In here, We implement the Employee Repository by inhering the IGenericRepository and IEmployeeRespository. In that case, we could override functions that do not implement the database logic with the Generic Repository and then could add the operations for that functions as above code.
Now we have to implement the Unit of Work in our project. Basically, I explained what unit of work in the above section is. Now we have to learn it with the Example.
In that case, I create the Configuration folder in the root directory of the project folder. Then we need to create the IUnitOfWork interface inside the configuration folder as following code.
IUnitOfWork.cs
Now we have built one repository with the Generic Repository pattern. We could inject the repositories that we implement in our project and then could access the data. But when we have a lot of repositories, we need to inject all of them. It's not good practice. In that case, we could use the unit of work to wrap all the repositories into a single object.
The Unit of Work is in control of exposing the relevant Repositories and Committing Changes to the DataSource in order to ensure a complete transaction with no data loss.
Now we have to implement this interface. In that case, create UnitOfWork class inside the configuration folder as the following code.
UnitOfWork.cs
We are injecting the DBContext and ILogger and implementing the CompleteAsync and the Dispose functions to use when the commit/update/remove operations with the database were.
Now navigate to startup class and need to register IUnitOfWork interface in our project as follows.
// Adding the Unit of work to the DI container
services.AddScoped<IUnitOfWork, UnitOfWork>();
We have only to register IUnitOfWork. We don't need to register other repositories as we are doing in the basic repository pattern. Because we inject all of the repositories in the IUnitOfWork, then we could access them through it.
Then we have to implement the controller in our project. In that case, We have to create the controller called EmployeeController inside the Controllers folder, as below code.
EmployeeController.cs
We inject the IUnitOfWork as the object in this controller. Then we have to use the unit of work to add the services and logic to the related methods in this controller.
Now we have to run this project. And then we could access our ASP.NET Core Web API as below figure.
We discuss some points such as Repository pattern, Non-Generic and Generic repository pattern, Unit Of Work and its benefits, and how to implement a unit of work with the repository pattern in the ASP.NET Core Web API project to get the basic idea about it with this article.
#viastudy
0 Comments