One-to-one relations

One-to-one is a relation where A contains only one instance of B, and B contains only one instance of A.Let’s take for example User and Profile entities.User can have only a single profile, and a single profile is owned by only a single user.

  1. import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
  2. @Entity()
  3. export class Profile {
  4. @PrimaryGeneratedColumn()
  5. id: number;
  6. @Column()
  7. gender: string;
  8. @Column()
  9. photo: string;
  10. }
  1. import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
  2. import {Profile} from "./Profile";
  3. @Entity()
  4. export class User {
  5. @PrimaryGeneratedColumn()
  6. id: number;
  7. @Column()
  8. name: string;
  9. @OneToOne(type => Profile)
  10. @JoinColumn()
  11. profile: Profile;
  12. }

Here we added @OneToOne to the profile and specify the target relation type to be Profile.We also added @JoinColumn which is required and must be set only on one side of the relation.The side you set @JoinColumn on, that side’s table will contain a “relation id” and foreign keys to target entity table.

This example will produce following tables:

  1. +-------------+--------------+----------------------------+
  2. | profile |
  3. +-------------+--------------+----------------------------+
  4. | id | int(11) | PRIMARY KEY AUTO_INCREMENT |
  5. | gender | varchar(255) | |
  6. | photo | varchar(255) | |
  7. +-------------+--------------+----------------------------+
  8. +-------------+--------------+----------------------------+
  9. | user |
  10. +-------------+--------------+----------------------------+
  11. | id | int(11) | PRIMARY KEY AUTO_INCREMENT |
  12. | name | varchar(255) | |
  13. | profileId | int(11) | FOREIGN KEY |
  14. +-------------+--------------+----------------------------+

Again, @JoinColumn must be set only on one side of relation - the side that must have the foreign key in the database table.

Example how to save such a relation:

  1. const profile = new Profile();
  2. profile.gender = "male";
  3. profile.photo = "me.jpg";
  4. await connection.manager.save(profile);
  5. const user = new User();
  6. user.name = 'Joe Smith';
  7. user.profile = profile;
  8. await connection.manager.save(user);

With cascades enabled you can save this relation with only one save call.

To load user with profile inside you must specify relation in FindOptions:

  1. const userRepository = connection.getRepository(User);
  2. const users = await userRepository.find({ relations: ["profile"] });

Or using QueryBuilder you can join them:

  1. const users = await connection
  2. .getRepository(User)
  3. .createQueryBuilder("user")
  4. .leftJoinAndSelect("user.profile", "profile")
  5. .getMany();

With eager loading enabled on a relation you don’t have to specify relation or join it - it will ALWAYS be loaded automatically.

Relations can be uni-directional and bi-directional.Uni-directional are relations with a relation decorator only on one side.Bi-directional are relations with decorators on both sides of a relation.

We just created a uni-directional relation. Let’s make it bi-directional:

  1. import {Entity, PrimaryGeneratedColumn, Column, OneToOne} from "typeorm";
  2. import {User} from "./User";
  3. @Entity()
  4. export class Profile {
  5. @PrimaryGeneratedColumn()
  6. id: number;
  7. @Column()
  8. gender: string;
  9. @Column()
  10. photo: string;
  11. @OneToOne(type => User, user => user.profile) // specify inverse side as a second parameter
  12. user: User;
  13. }
  1. import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
  2. import {Profile} from "./Profile";
  3. @Entity()
  4. export class User {
  5. @PrimaryGeneratedColumn()
  6. id: number;
  7. @Column()
  8. name: string;
  9. @OneToOne(type => Profile, profile => profile.user) // specify inverse side as a second parameter
  10. @JoinColumn()
  11. profile: Profile;
  12. }

We just made our relation bi-directional. Note, inverse relation does not have a @JoinColumn.@JoinColumn must only be on one side of the relation - on the table that will own the foreign key.

Bi-directional relations allow you to join relations from both sides using QueryBuilder:

  1. const profiles = await connection
  2. .getRepository(Profile)
  3. .createQueryBuilder("profile")
  4. .leftJoinAndSelect("profile.user", "user")
  5. .getMany();