How an ORM Works
You've probably used an ORM — Hibernate in Java, SQLAlchemy in Python, GORM in Go, Entity Framework Core in C# — or you will soon. Each has its own API, but they're all solving the same problem the same way, and once you understand the underlying pattern, every one of them reads as "oh, that's the same idea, named differently." That's the goal here: not a tour of one library, but the concepts every ORM shares, so the next ORM you meet is mostly vocabulary.
The core problem is the object-relational impedance mismatch: your code thinks in objects with references to other objects, but a relational database thinks in rows, columns, and foreign keys. An Object-Relational Mapper is the layer that translates between those two worlds — turning objects into rows and back, tracking what you changed, and generating the SQL. The mental model to hold is that an ORM is doing four jobs: mapping (objects ↔ tables), identity & tracking (remembering which objects came from where and what changed), loading (deciding when to fetch related data), and translating (turning your queries into SQL). Hold those four jobs and any ORM's behavior — including its surprises — becomes predictable.
📝 This is a concept guide, deliberately language-agnostic — code samples are short pseudocode, and each idea links to where you've seen it concretely: Hibernate & JPA, SQLAlchemy, GORM, and EF Core. It assumes basic databases — tables, keys, joins, transactions (What a Database Is, Relationships & Keys).
How to read this
Read in order — each phase is one of the jobs an ORM does, building from the mismatch up to the trade-offs. Phases carry difficulty badges.
The phases
- What an ORM Is (the Mismatch) 🟢 — objects vs rows, and the four jobs an ORM does.
- Mapping Objects to Tables 🟡 — classes↔tables, fields↔columns, references↔foreign keys.
- The Identity Map & Unit of Work 🔴 — one object per row, and batching changes into one commit.
- Change Tracking & Dirty Checking 🔴 — how the ORM knows what to UPDATE without you telling it.
- Lazy Loading & the N+1 Trap 🔴 — when related data loads, and the query explosion every ORM can cause.
- Building the Query (to SQL) 🟡 — how a query builder / object query becomes parameterized SQL.
- When Not to Use an ORM 🟢 — the honest limits, raw SQL, and where to go next.
The throughline: an ORM maps objects to rows, keeps an identity map + unit of work to track them, loads related data on some strategy, and translates your queries to SQL. Four jobs — learn them once, recognize them everywhere.