Part 6 · 1 chapters · ~8 min
The Reference Implementations
Hibernate and JPA (persistence context, flush modes, dirty checking, HQL and Criteria, N+1 and MultipleBagFetchException), ActiveRecord's conventions and loading strategies, SQLAlchemy's Core and ORM layers, the Django ORM's QuerySets, Entity Framework, and what the JavaScript ecosystem has yet to rebuild.
10
Four mature designs
code
# SQLAlchemy 2.0: Core expressions and the ORM unit of work in one library
from sqlalchemy import select, update
from sqlalchemy.orm import Session, selectinload
with Session(engine) as s, s.begin():
accts = s.scalars(select(Account).where(Account.owner_id == uid).options(selectinload(Account.postings))).all()
s.execute(update(Account).where(Account.id == aid, Account.balance_kobo >= amt)
.values(balance_kobo=Account.balance_kobo - amt)) # drop to Core for an atomic update
// Hibernate: fetch a graph in one query, and batch the rest
@EntityGraph(attributePaths = {"account", "account.owner"}) List<Transfer> findTop50ByOrderByCreatedAtDesc();
// hibernate.default_batch_fetch_size=50 turns remaining lazy loads into IN batchesTHE REFERENCE IMPLEMENTATIONS
what the mature ORMs got right
swipe the figure sideways, or tap expand for full screen
1/6
Hibernate
Hibernate (and the JPA standard) defined the persistence context: an identity map plus dirty checking, with flush modes deciding when SQL is sent. Famous problems: N+1 with lazy collections, MultipleBagFetchException when fetching two collections, LazyInitializationException outside sessions.
the most complete, the most complexN+1, bag fetch, lazy init errors