Reference / Symfony
/

Doctrine ORM Basics

Object-relational mapper. You write entities; Doctrine translates them to SQL via a unit-of-work pattern.

Foundational
  • Entities are plain PHP classes annotated with `#[ORM\Entity]` and `#[ORM\Column]` attributes.
  • The `EntityManager` is the central API: `persist()` schedules an insert/update, `remove()` schedules a delete, `flush()` runs queued operations as one transaction.
  • Repositories are the read side: `EntityManager::getRepository(User::class)` or inject a custom repository class.
  • Doctrine tracks changes automatically — modifying an attached entity then calling `flush()` writes the diff.
  • Lifecycle callbacks (`#[ORM\PrePersist]`, `#[ORM\PreUpdate]`) run inside the unit-of-work; keep them simple.
#[ORM\Entity]
class User
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 180, unique: true)]
    private string $email;
}

Common gotchas

  • Forgetting to `flush()` is the #1 "why didn't my change save?" cause.
  • Lifecycle callbacks fire only inside the unit-of-work — they do NOT fire on `UPDATE` queries you write by hand via DQL.