Identifiers
Every entity needs an identifier: it is how find(), update() and delete()
locate a row. One or more #[Id] properties declare it, and a class with none
throws MappingException.
Generated by the database
#[Id]
#[Generated]
public int $id;
The column is left out of the insert and the value the database assigned is
written back onto the entity afterwards. This works on every supported driver,
whether the value comes from RETURNING or from lastInsertId().
If the database reports no generated value, insert() throws
PersistenceException rather than leaving the property uninitialised.
Assigned by the application
Leave #[Generated] off and the value you set is written like any other column.
#[Entity]
final class Country
{
#[Id]
public string $code;
public string $name;
}
$country = new Country();
$country->code = 'nl';
$country->name = 'Netherlands';
$countries->insert($country);
Nothing is read back, because nothing was generated.
An assigned identifier has to be set before insert(). An uninitialised
property throws PersistenceException naming it, rather than writing a row with
a value the package invented.
Composite
More than one #[Id] makes the identifier composite.
#[Entity(table: 'memberships')]
final class Membership
{
#[Id]
public int $teamId;
#[Id]
public int $userId;
public string $role;
}
find() then takes an array keyed by property name, not column name:
$memberships->find(['teamId' => 1, 'userId' => 2]);
| What you pass | What happens |
|---|---|
| An array with every identifier property | The row is looked up. |
| An array missing one | InvalidIdentifierException, naming the property. |
| A scalar | InvalidIdentifierException: a composite identifier was expected. |
| Extra keys that are not identifier properties | Ignored. |
A composite identifier is never read back from an insert. The database reports
one generated key at most, so #[Generated] on a composite identifier property
has nothing to return; set the values yourself.
Which identifier a store uses
update() and delete() read the identifier off the entity you hand them, so
the object has to carry the values that locate its row. For a generated
identifier that means the entity came from a find() or has been through
insert().
An identifier that matches more than one row makes update() and delete()
throw PersistenceException, described in
what a write returns.