Design Patterns - Unit of Work Pattern in C# using MongoDB (with transactions)

Before you look at the Unit of Work pattern example in C# using MongoDB, you can see my post about what is the Unit of Work pattern.
Unit of Work interface in C#
public interface IUnitOfWork
{
IDisposable Session { get; }
void AddOperation(Action operation);
void CleanOperations();
Task CommitChanges();
}
About this code snippet:
- The property
Session
will be replaced by the MongoDB session object in the implementation of the Unit of Work. - The method
AddOperation
is used to add operations to the transaction. - The method
CleanOperations
clean all the operations (Before the execution of the transaction). - The method
CommitChanges
execute all operations in the transaction.
Implementation of the Unit of Work in C# using MongoDB
public sealed class UnitOfWork : IUnitOfWork
{
private IClientSessionHandle session { get; }
public IDisposable Session => this.session;
private List<Action> _operations { get; set; }
public UnitOfWork()
{
var mongoClient = new MongoClient("connectionString");
this.session = mongoClient.StartSession();
this._operations = new List<Action>();
}
public void AddOperation(Action operation)
{
this._operations.Add(operation);
}
public void CleanOperations()
{
this._operations.Clear();
}
public async Task CommitChanges()
{
this.session.StartTransaction();
this._operations.ForEach(o =>
{
o.Invoke();
});
await this.session.CommitTransactionAsync();
this.CleanOperations();
}
}
About this code snippet:
- The constructor starts a MongoDB session.
- The property
Session
returns the MongoDB session object.
Repository interface in C#
public interface IProductRepository
{
void Add(IProduct product);
void Update(IProduct product);
void Remove(ProductId id);
}
About this code snippet:
- For this example, I am only including the methods that will go inside a transaction.
- These actions are not asynchronous because they are not executed instantly, instead, they just add operations to the transaction.
Implementation of the Repository in C# using MongoDB
public sealed class ProductRepository : IProductRepository
{
private readonly IMongoDatabase _database;
private readonly IMongoCollection<ProductMongoEntity> _productsCollection;
private readonly IUnitOfWork _unitOfWork;
public ProductRepository(IUnitOfWork unitOfWork)
{
this._unitOfWork = unitOfWork;
var mongoClient = new MongoClient("connectionString");
this._database = mongoClient.GetDatabase("databaseName");
this._productsCollection = this._database.GetCollection<ProductMongoEntity>("collectionName");
}
public void Add(IProduct product)
{
Action operation = () => this._productsCollection.InsertOne(this._unitOfWork.Session as IClientSessionHandle, product);
this._unitOfWork.AddOperation(operation);
}
public void Update(IProduct product)
{
Action operation = () => this._productsCollection.ReplaceOne(this._unitOfWork.Session as IClientSessionHandle, x => x.Id == product.Id, product);
this._unitOfWork.AddOperation(operation);
}
public void Remove(ProductId id)
{
Action operation = () => this._productsCollection.DeleteOne(this._unitOfWork.Session as IClientSessionHandle, x => x.Id == id.Id);
this._unitOfWork.AddOperation(operation);
}
}
About this code snippet:
- The Unit of Work is injected into the repository because it is necessary to know the MongoDB session.
- Each method of the Repository creates an action with the data of the operation to perform and adds it to the list of operations of the Unit of Work.
Categories
Automation scripting Development tools Front end web development Infrastructure Kubernetes Programming guide Security Software architectureTags
Recent Posts
Restart Kubernetes pods following a schedule using Helm
Restart Kubernetes pods following a schedule using Kubectl
Create an Azure Key Vault with RBAC role assignments using Terraform
Get the download url of the latest GitHub release using Bash
Get the download url of the latest GitHub release using PowerShell