Monday, November 17, 2025

Architecture - Unit of Work (UOW) Pattern

1️⃣ What is Unit of Work?

Unit of Work (UoW) is a design pattern that:

  • Tracks changes made during a business transaction
  • Ensures all operations either succeed together (Commit)
  • Or fail together (Rollback)
  • Avoids partial writes to the database
  • Works like a transaction manager for repositories

📌 Simple Definition

UoW ensures that multiple database operations inside a business use case are treated as one atomic unit — either fully saved or fully reverted.


 


2️⃣ Why Do We Need Unit of Work?

Problems Without UoW

  • Calling multiple repositories → each saves independently
  • Leads to partial updates, inconsistent data, and race conditions
  • No coordination between repositories

With UoW

  • All repository actions are batched
  • Saved only when Commit() is called
  • If error occurs → Rollback() ensures consistency

3️⃣ How UoW Works Internally

EF Core already implements UoW concepts:

  • DbContext tracks changes (UoW)
  • DbContext.SaveChanges() = Commit

But in DDD or layered architecture, we wrap DbContext inside a custom UoW interface.


4️⃣ Commit & Rollback Explained

👉 Commit

  • Saves all tracked changes to database
  • Calls SaveChanges() or SaveChangesAsync()
  • Ensures all operations succeed

👉 Rollback

  • Cancels the transaction
  • Discards all uncommitted changes
  • Database remains unchanged

5️⃣ Unit of Work Flow (Simple)

Start UoW ↓ Use Repositories ↓ Make Changes (Add/Update/Delete) ↓ Commit() → All changes are saved OR Rollback() → All changes discarded

6️⃣ UoW with EF Core — Code Example

IUnitOfWork.cs

public interface IUnitOfWork : IDisposable { IProductRepository Products { get; } IOrderRepository Orders { get; } Task<int> CommitAsync(); // Commit = Save void Rollback(); // Rollback = Discard changes }

UnitOfWork.cs

public class UnitOfWork : IUnitOfWork { private readonly AppDbContext _context; public UnitOfWork(AppDbContext context) { _context = context; Products = new ProductRepository(context); Orders = new OrderRepository(context); } public IProductRepository Products { get; private set; } public IOrderRepository Orders { get; private set; } public async Task<int> CommitAsync() { return await _context.SaveChangesAsync(); } public void Rollback() { // Discard changes tracked by DbContext foreach (var entry in _context.ChangeTracker.Entries()) { switch (entry.State) { case EntityState.Modified: case EntityState.Deleted: case EntityState.Added: entry.State = EntityState.Detached; break; } } } public void Dispose() { _context.Dispose(); } }

7️⃣ Using Unit of Work — Example

Example Business Use Case: PlaceOrder

public async Task PlaceOrder(Order order) { using var uow = _unitOfWork; try { uow.Orders.Add(order); uow.Products.UpdateStock(order.ProductId, -order.Quantity); await uow.CommitAsync(); // Commit all } catch (Exception) { uow.Rollback(); // Discard changes throw; } }

✔ Both repositories share the same DbContext

✔ UoW ensures either:

  • Order saved + Stock updated → together
  • Or nothing saved → Rollback

8️⃣ Interview-Friendly Summary

Repository

  • Provides an abstraction over data logic
  • Works per entity (ProductRepository, OrderRepository)

Generic Repository

  • Provides base CRUD logic for all entities
  • Reduces duplication

Unit of Work

  • Controls multiple repositories
  • One transaction for the whole business operation
  • Offers Commit() and Rollback()
  • Maintains consistency

No comments:

Post a Comment

CI/CD - Safe DB Changes/Migrations

Safe DB Migrations means updating your database schema without breaking the running application and without downtime . In real systems (A...