多对一 / 一对多关系
非官方测试版翻译
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
多对一/一对多关系是指:A 包含多个 B 的实例,而 B 只包含一个 A 的实例。
以 User 和 Photo 实体为例:
一个用户可以拥有多张照片,但每张照片仅属于一个用户。
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[]
}
这里我们在 photos 属性上添加了 @OneToMany 装饰器,并将目标关系类型指定为 Photo。
在 @ManyToOne / @OneToMany 关系中可省略 @JoinColumn。
@OneToMany 不能脱离 @ManyToOne 单独存在。
若想使用 @OneToMany,则必须配置 @ManyToOne。但反向操作不是必须的:如果只需 @ManyToOne 关系,可不定义相关实体上的 @OneToMany。
在设置 @ManyToOne 的位置,其相关实体将拥有"关系 ID"和外键。
此示例将生成以下表结构:
+-------------+--------------+----------------------------+
| photo |
+-------------+--------------+----------------------------+
| id | int | PRIMARY KEY AUTO_INCREMENT |
| url | varchar(255) | |
| userId | int | FOREIGN KEY |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| user |
+-------------+--------------+----------------------------+
| id | int | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
+-------------+--------------+----------------------------+
保存此类关系的示例:
const photo1 = new Photo()
photo1.url = "me.jpg"
await dataSource.manager.save(photo1)
const photo2 = new Photo()
photo2.url = "me-and-bears.jpg"
await dataSource.manager.save(photo2)
const user = new User()
user.name = "John"
user.photos = [photo1, photo2]
await dataSource.manager.save(user)
或采用替代方案:
const user = new User()
user.name = "Leo"
await dataSource.manager.save(user)
const photo1 = new Photo()
photo1.url = "me.jpg"
photo1.user = user
await dataSource.manager.save(photo1)
const photo2 = new Photo()
photo2.url = "me-and-bears.jpg"
photo2.user = user
await dataSource.manager.save(photo2)
启用级联功能后,仅需单次 save 调用即可保存此关系。
要加载包含照片的用户数据,必须在 FindOptions 中指定关系:
const userRepository = dataSource.getRepository(User)
const users = await userRepository.find({
relations: {
photos: true,
},
})
// or from inverse side
const photoRepository = dataSource.getRepository(Photo)
const photos = await photoRepository.find({
relations: {
user: true,
},
})
或使用 QueryBuilder 进行关联查询:
const users = await dataSource
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.photos", "photo")
.getMany()
// or from inverse side
const photos = await dataSource
.getRepository(Photo)
.createQueryBuilder("photo")
.leftJoinAndSelect("photo.user", "user")
.getMany()
当关系启用即时加载(eager loading)时,无需在查找命令中显式声明关系——系统将始终自动加载。
若使用 QueryBuilder 则会禁用即时加载,此时必须通过 leftJoinAndSelect 加载关系。