Repository and Unit of Work Pattern - Details of the Unit of Work Pattern
Learn how to group operations into a single transaction with the Unit of Work pattern, complete with a practical implementation.
Summary
This article is part of a series covering the Repository and Unit of Work patterns:
- General Introduction and Usefulness in Enterprise Projects
- Details of the Repository Pattern
- Details of the Unit of Work Pattern
- Compatibility and Limitations with Microservices
- Practical Example: Joint Usage in an E-commerce Platform
- Conclusion and Lessons Learned
Unit of Work Pattern: Managing Transactions
The Unit of Work Pattern is designed to group multiple operations into a single coherent transaction. It ensures that all modifications are either successfully executed or rolled back in case of failure.
Unit of Work Interface Example
public interface IUnitOfWork : IDisposable
{
IRepository<T> Repository<T>() where T : class;
Task<int> SaveChangesAsync();
}
Unit of Work Implementation
Here is a basic implementation:
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
private readonly Dictionary<string, object> _repositories = new();
public UnitOfWork(DbContext context)
{
_context = context;
}
public IRepository<T> Repository<T>() where T : class
{
var typeName = typeof(T).Name;
if (!_repositories.ContainsKey(typeName))
{
var repositoryInstance = new Repository<T>(_context);
_repositories[typeName] = repositoryInstance;
}
return (IRepository<T>)_repositories[typeName];
}
public async Task<int> SaveChangesAsync() => await _context.SaveChangesAsync();
public void Dispose() => _context.Dispose();
}
This pattern isolates transaction management and coordinates repositories within a single unit.