Unit of Work
Maintains a list of operations affected by a business transaction and coordinates their writing.
Context
A business operation modifies multiple aggregates (Order, Inventory, Audit). You want to commit ALL or nothing.
Problem
Without coordination, you might save the order but fail to decrement stock.
Solution
A UnitOfWork groups operations and commits them with SaveChanges() within a single transaction.
#Example in C#
public interface IUnitOfWork : IAsyncDisposable
{
IOrderRepository Orders { get; }
IInventoryRepository Inventory { get; }
Task<int> SaveChangesAsync(CancellationToken ct = default);
}
public class EfUnitOfWork : IUnitOfWork
{
private readonly AppDbContext _db;
public EfUnitOfWork(AppDbContext db, IOrderRepository o, IInventoryRepository i)
{ _db = db; Orders = o; Inventory = i; }
public IOrderRepository Orders { get; }
public IInventoryRepository Inventory { get; }
public Task<int> SaveChangesAsync(CancellationToken ct = default) => _db.SaveChangesAsync(ct);
public ValueTask DisposeAsync() => _db.DisposeAsync();
}
// Usage
await using var uow = factory.Create();
uow.Orders.Add(order);
uow.Inventory.Reserve(order.Items);
await uow.SaveChangesAsync();In EF Core,
DbContextis already a Unit of Work. Creating another one on top is usually redundant.
When NOT to use it
- If your ORM already implements Unit of Work (EF, NHibernate).
- If operations span processes (in which case you need Saga / Outbox).
#extra #persistence #transaction