• 多对一/一对多的关系

    多对一/一对多的关系

    多对一/一对多是指 A 包含多个 B 实例的关系,但 B 只包含一个 A 实例。让我们以UserPhoto 实体为例。User 可以拥有多张 photos,但每张 photo 仅由一位 user 拥有。

    1. import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm";
    2. import { User } from "./User";
    3. @Entity()
    4. export class Photo {
    5. @PrimaryGeneratedColumn()
    6. id: number;
    7. @Column()
    8. url: string;
    9. @ManyToOne(type => User, user => user.photos)
    10. user: User;
    11. }
    1. import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm";
    2. import { Photo } from "./Photo";
    3. @Entity()
    4. export class User {
    5. @PrimaryGeneratedColumn()
    6. id: number;
    7. @Column()
    8. name: string;
    9. @OneToMany(type => Photo, photo => photo.user)
    10. photos: Photo[];
    11. }

    这里我们将@ManyToOne添加到photos属性中,并将目标关系类型指定为Photo。你也可以在@ManyToOne /@OneToMany关系中省略@JoinColumn。没有@ManyToOne@OneToMany就不可能存在。如果你想使用@OneToMany,则需要@ManyToOne。在你设置@ManyToOne的地方,相关实体将有”关联 id”和外键。

    此示例将生成以下表:

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

    如何保存这种关系:

    1. const photo1 = new Photo();
    2. photo1.url = "me.jpg";
    3. await connection.manager.save(photo1);
    4. const photo2 = new Photo();
    5. photo2.url = "me-and-bears.jpg";
    6. await connection.manager.save(photo2);
    7. const user = new User();
    8. user.name = "John";
    9. user.photos = [photo1, photo2];
    10. await connection.manager.save(user);

    或者你可以选择:

    1. const user = new User();
    2. user.name = "Leo";
    3. await connection.manager.save(user);
    4. const photo1 = new Photo();
    5. photo1.url = "me.jpg";
    6. photo1.user = user;
    7. await connection.manager.save(photo1);
    8. const photo2 = new Photo();
    9. photo2.url = "me-and-bears.jpg";
    10. photo2.user = user;
    11. await connection.manager.save(photo2);

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

    要在内部加载带有 photos 的 user,必须在FindOptions中指定关系:

    1. const userRepository = connection.getRepository(User);
    2. const users = await userRepository.find({ relations: ["photos"] });
    3. // or from inverse side
    4. const photoRepository = connection.getRepository(Photo);
    5. const photos = await photoRepository.find({ relations: ["user"] });

    或者使用QueryBuilder:

    1. const users = await connection
    2. .getRepository(User)
    3. .createQueryBuilder("user")
    4. .leftJoinAndSelect("user.photos", "photo")
    5. .getMany();
    6. // or from inverse side
    7. const photos = await connection
    8. .getRepository(Photo)
    9. .createQueryBuilder("photo")
    10. .leftJoinAndSelect("photo.user", "user")
    11. .getMany();

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