多对一/一对多的关系

多对一/一对多是指 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();

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