• 一对一

    一对一

    一对一是一种 A 只包含一个 B 实例,而 B 只包含一个 A 实例的关系。我们以UserProfile实体为例。

    用户只能拥有一个配置文件,并且一个配置文件仅由一个用户拥有。

    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. }

    这里我们将@OneToOne添加到profile并将目标关系类型指定为Profile。我们还添加了@JoinColumn,这是必选项并且只能在关系的一侧设置。你设置@JoinColumn的哪一方,哪一方的表将包含一个”relation id”和目标实体表的外键。

    此示例将生成以下表:

    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. +-------------+--------------+----------------------------+

    同样,@JoinColumn必须仅设置在关系的一侧且必须在数据库表中具有外键的一侧。

    该例子展示如何保存这样的关系:

    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);

    启用级联后,只需一次save调用即可保存此关系。

    要加载带有配置文件的用户,必须在FindOptions中指定关系:

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

    或者使用QueryBuilder:

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

    通过在关系上启用预先加载,你不必指定关系或手动加入,它将始终自动加载。

    关系可以是单向的和双向的。单向是仅在一侧与关系装饰器的关系。双向是与关系两侧的装饰者的关系。

    我们刚刚创建了一个单向关系。 让我们将它改为双向:

    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) // 将另一面指定为第二个参数
    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) // 指定另一面作为第二个参数
    10. @JoinColumn()
    11. profile: Profile;
    12. }

    我们只是创建了双向关系。 注意,反向关系没有@JoinColumn@JoinColumn必须只在关系的一侧且拥有外键的表上。

    双向关系允许你使用QueryBuilder从双方加入关系:

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