Problem
When each repository call commits on its own, a use case that changes several objects can fail halfway and leave inconsistent data. Developers also repeat transaction handling in every operation.
Also known as: uow, transaction-scope
Track changes made during a business operation and commit them together as a single atomic transaction.
When each repository call commits on its own, a use case that changes several objects can fail halfway and leave inconsistent data. Developers also repeat transaction handling in every operation.
Martin Fowler describes a unit of work as maintaining a list of objects affected by a business transaction and coordinating the writing out of changes. Most ORMs, such as Hibernate sessions, Entity Framework contexts, and SQLAlchemy sessions, implement it internally.
The application service opens a unit, loads aggregates through repositories, calls domain methods, and commits.
with uow: # begins transaction
order = uow.orders.get(order_id)
order.confirm()
uow.stock.reserve(order.lines)
uow.commit() # flush all changes atomically
# exiting without commit rolls back
begin -> load -> mutate -> commit (all writes in one DB transaction)
\-> error -> rollback
Domain events raised by aggregates can be collected by the unit and dispatched only after a successful commit, or written to an outbox table in the same transaction.
None — uses database transactions
Low — watch transaction duration
Medium — session and tracking semantics
Unit spanning remote calls and holding locks while waiting
Forgetting to commit, silently dropping changes
Reusing a unit across requests and leaking stale tracked entities