.Net Core App -Repository Pattern and Unit of Work with transaction using Dapper
“Keep it Simple” is the motivation behind the creation of Dapper.
What is Dapper?
Dapper is a light weight Object-Relational Mapping (ORM) framework developed by Stack Exchange (brains behind Stack Overflow)
The moment we hear this acronym ORM first thing which comes to mind for a .Net developer is Entity Framework. Dapper is also a similar kind of framework but we can consider Dapper as a “Micro-ORM” because EF provides wide range of features when compared to Dapper.
Cool, now lets get into code
In this example I am going to use a simple money transfer scenario.
User A can send money to user B and the transaction detail will be persisted in database for future reference
Architecture
Repository
Lets gets started by creating a repository
Our use case needs two repositories
- User Repository for managing user account operations
- Transfer Repository for tracking the money transfers
We will be injecting SqlConnection using which we will be performing the CRUD operations and we also be injecting IDBTransaction instance to repository.
This can be done in individually in each repository or we can create a base repository with these properties and other repositories can inherit the base repository.
All the dapper methods are extension methods to SqlConnection class type and we have an optional parameter to pass the transaction instance.
For transaction we don't have any special class from Dapper, we will be using IDBTransaction which we normally use for SqlConnection transactions.
Below is the sample repository code
Unit of work
The main reason behind unit of work is to minimize the number of calls made to database. Unit of work will keep track of the changes made to entities and finally push the changes in to database on commit. Same pattern can be used to maintain a transaction.
A single application can have multiple entities and repositories. We can expose all the repository instances via unit of work which a controller or consumer can use.
In our case we will be injecting IDBTransaction instance and repository instances to our unit of work class.
Unit of work will expose a commit method using which the client can save the changes to db.
In our case we will be calling commit method exposed by the IDBTransaction inside our commit method, in case if there is any exception we can roll back the transaction.
Now lets move on to core part of the implementation
Startup.cs
We need to share same IDBTransaction instance across the repository and the unit of work for a given request cycle, so we can inject it as a scoped instance.
In order to obtain this instance we need a SQL connection, so lets inject a SqlConnection as a scoped instance and from that we can obtain transaction instance from this connection
Lets consume the service from controller
Controller.cs
Lets write our business logic in controller and commit the changes using unit of work instance.
Note: Since we inject the transaction instance from Startup.cs all the queries which are executed as part of the same SqlConnection will require a transaction instance.
Complete code can be found in this GitHub repo
Please feel free to share your thoughts or feedback in comments section. In case if this article helped you to learn something please leave a clap below
Happy Coding !!!