By combinining link cardinality and exclusivity constraints, we can model every kind of relationship: one-to-one, one-to-many, many-to-one, and many-to-many.
Relation type |
Cardinality |
Exclusive |
One-to-one |
|
Yes |
One-to-many |
|
Yes |
Many-to-one |
|
No |
Many-to-many |
|
No |
Many-to-one relationships typically represent concepts like ownership,
membership, or hierarchies. For example, Person
and Shirt
. One person
may own many shirts, and a shirt is (usually) owned by just one person.
type Person {
required property name -> str
}
type Shirt {
required property color -> str;
link owner -> Person;
}
Remember, links are single
by default, so each shirt only corresponds to
one person. In the absence of any exclusivity constraints, multiple shirts can
link to the same person. Thus, we have a one-to-many relationship between
Person
and Shirt
.
When fetching a Person
, it’s possible to deeply fetch their collection of
Shirts
by traversing the Shirt.owner
link in reverse. This is known
as a backlink; read the select docs to
learn more.
Conceptually, one-to-many and many-to-one relationships are identical; the “directionality” of a relation is just a matter of perspective.
In practice, though, there are multiple ways to represent this kind of relation
in EdgeDB. Here’s the same person-shirt relation represented with a multi
link
.
type Person {
required property name -> str;
multi link shirts -> Shirt {
# ensures a one-to-many relationship
constraint exclusive;
}
}
type Shirt {
required property color -> str;
}
Don’t forget the exclusive constraint! This is required to ensure that each
Shirt
corresponds to a single Person
. Without it, the relationship
will be many-to-many.
Under the hood, a multi link
is stored in an intermediate association
table, whereas a single
link
is stored as a column in the object type where it is declared. As a
result, single links are marginally more efficient. Generally single
links
are recommended when modeling 1:N relations.
Under a one-to-one relationship, the source object links to a single instance of the target type, and vice versa. As an example consider a schema to represent assigned parking spaces.
type Employee {
required property name -> str;
link assigned_space -> ParkingSpace {
constraint exclusive;
}
}
type ParkingSpace {
required property number -> int64;
}
All links are single
unless otherwise specified, so no Employee
can
have more than one assigned_space
. Moreover, the
exclusive
constraint guarantees that a given ParkingSpace
can’t be assigned to multiple Employees
at once. Together the single
link
and exclusivity constraint constitute a one-to-one relationship.
A many-to-many relation is the least constrained kind of relationship. There
is no exclusivity or cardinality constraints in either direction. As an example
consider a simple app where Users
can “like” their favorite Movies
.
type User {
required property name -> str;
multi link likes -> Movie;
}
type Movie {
required property title -> str;
}
A user can like multiple movies. And in the absence of an exclusive
constraint, each movie can be liked by multiple users. Thus this is a
many-to-many relationship.