Unit of Work Pattern: Supermarket Checkout

The Unit of Work Pattern is a design pattern that helps coordinate multiple changes to data as one single transaction. Instead of saving changes to the database one by one, you make several changes in memory and then commit all of them together. If anything fails, the entire operation can be rolled back to maintain data consistency.

This pattern is especially useful when you’re updating several tables or entities that depend on each other. It groups all the changes into a single unit so you can commit or cancel them as a whole — reducing the risk of partial updates or inconsistent data.

Real-Life Analogy: Supermarket Checkout

Imagine you're in a supermarket. You walk around and collect several items — milk, bread, eggs. You place them all in your cart. While you're still shopping, you can add or remove things. But nothing is final until you go to the checkout and pay.

In this analogy:

  • Entities = The individual items you add to your cart
  • Unit of Work = The checkout process where everything is confirmed at once
  • Checkout = You swipe your card and finalise the purchase — all items are saved together
Supermarket Checkout analogy for Unit of Work Pattern
The Unit of Work groups multiple actions (like items in a cart) and saves them together — just like paying for everything in one go at a supermarket checkout.

Benefits of the Unit of Work Pattern

Unit of Work is most valuable when you deal with multiple related data changes that should be handled together. It helps enforce data integrity and transactional consistency across your application.

It also works well with repositories, allowing you to keep data access logic organised while centralising saves.

  • Transaction management – ensures all-or-nothing updates
  • Consistency – avoids half-saved states
  • Decouples logic from direct database access
  • Improves testability by isolating changes in memory

What to Implement

The pattern involves wrapping all related operations under a Unit of Work object. You prepare your changes first, then call a single method like Commit() or SaveChanges() to persist them.

  • IUnitOfWork: An interface that exposes the Commit() method
  • Concrete UnitOfWork: Coordinates repositories and calls SaveChanges() on DbContext
  • Repositories: Perform data operations and attach entities to the UnitOfWork

How It Works in C#

// IUnitOfWork.cs
public interface IUnitOfWork {
    IProductRepository Products { get; }
    IOrderRepository Orders { get; }
    void Commit();
}

// UnitOfWork.cs
public class UnitOfWork : IUnitOfWork {
    private readonly AppDbContext _context;
    public IProductRepository Products { get; }
    public IOrderRepository Orders { get; }

    public UnitOfWork(AppDbContext context,
                      IProductRepository products,
                      IOrderRepository orders) {
        _context = context;
        Products = products;
        Orders = orders;
    }

    public void Commit() {
        _context.SaveChanges();
    }
}

// Usage
public class OrderService {
    private readonly IUnitOfWork _unitOfWork;

    public OrderService(IUnitOfWork unitOfWork) {
        _unitOfWork = unitOfWork;
    }

    public void PlaceOrder() {
        _unitOfWork.Orders.Add(new Order());
        _unitOfWork.Products.DecreaseStock(5);
        _unitOfWork.Commit(); // everything saved at once
    }
}

When Should You Use It?

Use the Unit of Work pattern when:

  • You need to make multiple related changes in one logical operation
  • You’re working with repositories or domain-driven design (DDD)
  • You want to support rollback if something goes wrong mid-process
  • You need full control over when changes are saved to the database

When Not to Use It: For small apps or when each operation is already atomic and unrelated, Unit of Work may be overkill. Don’t use it if you only save one item at a time with no relation to other entities.

Where Is It Used in the Real World?

The Unit of Work Pattern is commonly used in .NET applications that use Entity Framework, where changes are tracked and saved together using the DbContext. It is especially helpful when working with multiple repositories or performing batch updates.

  • Enterprise applications with complex business logic
  • Ordering systems that update stock, orders, and payments in one go
  • Banking or accounting apps requiring strict consistency
  • ASP.NET Core apps with repository + unit of work setup

Final Thoughts

The Unit of Work Pattern is all about treating related changes as one operation. It keeps your data consistent and your code clean, especially when working with multiple entities or repositories.

Think of it as the checkout at a supermarket — you only confirm everything when you're ready to pay for all items together. That single action keeps your system reliable and your database safe from partial updates.