Skip to main content

Entity relations and inverse lookups

The term “entity relation” refers to the situation when an entity instance contains an instance of another entity within one of its fields. Type-wise this means that some entity (called the owning entity) has a field of a type that is some other, non-owning entity. Within the database, this is implemented as an (automatically indexed) foreign key column within the table mapped to the owning entity. A fieldName entity-typed field will map to a column named field_name_id. One-to-one and one-to-many relations are supported by Typeorm. The “many” side of the one-to-many relations is always the owning side. Many-to-many relations are modeled as two one-to-many relations with an explicit join table. An entity relation is always unidirectional, but it is possible to request the data on the owning entity from the non-owning one. To do so, define a field decorated @derivedFrom in the schema. Doing so will cause the Typeorm code generated by squid-typeorm-codegen and the GraphQL API served by squid-graphql-server to show a virtual (that is, not mapping to a database column) field populated via inverse lookup queries. The following examples illustrate the concepts.

One-to-one relations

The User entity references Account and owns the one-to-one relation. This is implemented as follows:
  • On the database side: the account property of the User entity maps to the account_id foreign key column of the user table referencing the account table.
  • On the TypeORM side: the account property of the User entity gets decorated with @OneToOne and @JoinColumn.
  • On the GraphQL side: sub-selection of the account property is made available in user-related queries. Sub-selection of the user property is made available in account-related queries.
Codegen adds the reverse @OneToOne property for the @derivedFrom field to the Account model.

Many-to-one/One-to-many relations

Here Transfer defines owns the two relations and Account defines the corresponding inverse lookup properties. This is implemented as follows:
  • On the database side: the from and to properties of the Transfer entity map to from_id and to_id foreign key columns of the transfer table referencing the account table.
  • On the TypeORM side: properties to and from of the Transfer entity class get decorated with @ManyToOne. Properties transfersTo and transfersFrom decorated with @OneToMany get added to the Account entity class.
  • On the GraphQL side: sub-selection of all relation-defined properties is made available in the schema.

Disabling a foreign-key constraint

Apply @disableForeignKeyConstraint to a nullable owning field when the database should store the referenced ID without enforcing that the target row exists:
The directive does not apply to lists, scalar fields, non-null fields, or @derivedFrom fields. The GraphQL relation still works when the referenced row exists.

Many-to-many relations

Many-to-many entity relations should be modeled as two one-to-many relations with an explicitly defined join table. Here is an example: