← All topics
🧩 Design Patterns

Unit of Work

Grouping repository operations into one atomic commit.

Unit of Work tracks a set of changes across (potentially several) repositories and commits them together in one transaction — SaveChanges() is EF Core's built-in Unit of Work. When you have multiple repositories that must succeed or fail together (e.g. debit one account, credit another), they should share the same DbContext instance so a single SaveChanges() call wraps both in one transaction, rather than each repository committing independently.

public interface IUnitOfWork
{
    IOrderRepository Orders { get; }
    IPaymentRepository Payments { get; }
    Task<int> SaveChangesAsync();
}

public class UnitOfWork(AppDbContext db, IOrderRepository orders, IPaymentRepository payments) : IUnitOfWork
{
    public IOrderRepository Orders => orders;
    public IPaymentRepository Payments => payments;
    public Task<int> SaveChangesAsync() => db.SaveChangesAsync();
}

Flashcards (2)

In EF Core terms, what IS Unit of Work, concretely?
tap to reveal answer
DbContext itself — it tracks all changes made through it, and a single SaveChanges() call commits them together in one transaction. A separate IUnitOfWork wrapper is mostly about making that explicit/injectable across multiple repositories.
Why must two repositories that need atomic commits share the same DbContext instance?
tap to reveal answer
SaveChanges() commits changes tracked by one DbContext in one transaction — if each repository has its own DbContext, their changes commit independently and you lose the all-or-nothing guarantee.