design·lab

Real-world combination

Repository + Unit of Work

Repository hides persistence behind a collection-like interface; Unit of Work tracks every change made through it and commits them all in one transaction.

✗ Problem

SQL scattered through business logic

Domain code calls the database directly. It's coupled to the DB, impossible to unit-test, and if the process dies mid-way, some writes land and others don't.

function placeOrder(order) {
  db.query('UPDATE stock SET qty=qty-1 WHERE id=?', [order.itemId]);
  // crash here → stock decremented, order row never written
  db.query('INSERT INTO orders ...', [order]);
}
Business logic knows table names and SQL syntax — swap the DB or write a unit test and everything breaks. And nothing wraps the two writes in one transaction.
✓ The combination

Collection-like interface + one transaction

A Repository looks like an in-memory collection (findById, add, remove) hiding the DB behind it. A Unit of Work tracks everything changed through repositories in this session and commits — or rolls back — as one transaction.

interface UserRepository {
  findById(id);
  add(user);
  remove(user);
}

// domain only knows the interface (DIP):
userRepo.add(newUser);
userRepo.remove(oldUser);
uow.commit();  // all-or-nothing
Domain
business logic
Repository
interface
UnitOfWork
tracks changes
DB
1 transaction
✓ See it live

Add, edit, delete — then commit or rollback

Buttons act through the repository. Every change is tracked as a pending change — nothing touches the database until you commit.

Repository (working view)

Database (committed)

Unit of Work — pending changes

0 pending changes
✓ Takeaway

Why the combination earns its keep

  • Swap the DB / test in memory: the domain only knows the repository interface — give it a fake for unit tests, a real one in production.
  • One transaction per business operation: the Unit of Work makes multi-entity writes atomic — commit everything, or nothing.
  • Persistence-ignorant domain: business logic never sees SQL, table names, or ORM sessions.
  • This is how ORMs work under the hood: EF Core's DbContext and Hibernate's Session are both Unit of Work + Repository.
  • Caution: keep repositories thin — no business rules inside, or they turn into a second domain layer.
🎯 Combines: Repository + Unit of Work behind an interface — pure Dependency Inversion + SRP (domain vs persistence).