多对一/一对多的关系
多对一/一对多是指 A 包含多个 B 实例的关系,但 B 只包含一个 A 实例。
让我们以User
和 Photo
实体为例。
User 可以拥有多张 photos,但每张 photo 仅由一位 user 拥有。
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm";
import { User } from "./User";
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column()
url: string;
@ManyToOne(() => User, user => user.photos)
user: User;
}
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm";
import { Photo } from "./Photo";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(() => Photo, photo => photo.user)
photos: Photo[];
}
这里我们将@OneToMany
添加到photos
属性中,并将目标关系类型指定为Photo
。
你可以在@ManyToOne
/ @OneToMany
关系中省略@JoinColumn
,除非你需要自定义关联列在数据库中的名称。
@ManyToOne
可以单独使用,但@OneToMany
必须搭配@ManyToOne
使用。
如果你想使用@OneToMany
,则需要@ManyToOne
。
在你设置@ManyToOne
的地方,相关实体将有"关联 id"和外键。
此示例将生成以下表:
+-------------+--------------+----------------------------+
| photo |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| url | varchar(255) | |
| userId | int(11) | |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| user |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
+-------------+--------------+----------------------------+
如何保存这种关系:
const photo1 = new Photo();
photo1.url = "me.jpg";
await connection.manager.save(photo1);
const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
await connection.manager.save(photo2);
const user = new User();
user.name = "John";
user.photos = [photo1, photo2];
await connection.manager.save(user);
或者你可以选择:
const user = new User();
user.name = "Leo";
await connection.manager.save(user);
const photo1 = new Photo();
photo1.url = "me.jpg";
photo1.user = user;
await connection.manager.save(photo1);
const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
photo2.user = user;
await connection.manager.save(photo2);
启用级联后,只需一次save
调用即可保存此关系。
要在内部加载带有 photos 的 user,必须在FindOptions
中指定关系:
const userRepository = connection.getRepository(User);
const users = await userRepository.find({ relations: ["photos"] });
// or from inverse side
const photoRepository = connection.getRepository(Photo);
const photos = await photoRepository.find({ relations: ["user"] });
或者使用QueryBuilder
:
const users = await connection
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.photos", "photo")
.getMany();
// or from inverse side
const photos = await connection
.getRepository(Photo)
.createQueryBuilder("photo")
.leftJoinAndSelect("photo.user", "user")
.getMany();
通过在关系上启用预先加载,你不必指定关系或手动加入,它将始终自动加载。