一对一关系
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
一对一关系指实体A仅包含实体B的一个实例,同时实体B也仅包含实体A的一个实例。
以 User 和 Profile 实体为例:
每个用户只能拥有一个个人资料,而每个个人资料仅归属于一个用户。
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number
@Column()
gender: string
@Column()
photo: string
}
import {
Entity,
PrimaryGeneratedColumn,
Column,
OneToOne,
JoinColumn,
} from "typeorm"
import { Profile } from "./Profile"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@OneToOne(() => Profile)
@JoinColumn()
profile: Profile
}
我们在 user 上添加了 @OneToOne 装饰器,并将目标关系类型指定为 Profile。
同时添加了必需的 @JoinColumn 装饰器,该装饰器必须且只能设置在关系的一方。
设置 @JoinColumn 的一方,其数据库表将包含"关系ID"及指向目标实体表的外键。
此示例将生成以下表结构:
+-------------+--------------+----------------------------+
| profile |
+-------------+--------------+----------------------------+
| id | int | PRIMARY KEY AUTO_INCREMENT |
| gender | varchar(255) | |
| photo | varchar(255) | |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| user |
+-------------+--------------+----------------------------+
| id | int | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
| profileId | int | FOREIGN KEY |
+-------------+--------------+----------------------------+
再次强调:@JoinColumn 必须且只能设置在关系的一方——即数据库表中需要包含外键的那方。
保存该关系的示例:
const profile = new Profile()
profile.gender = "male"
profile.photo = "me.jpg"
await dataSource.manager.save(profile)
const user = new User()
user.name = "Joe Smith"
user.profile = profile
await dataSource.manager.save(user)
启用级联功能后,仅需单次 save 调用即可保存此关系。
加载包含个人资料的用户数据时,需在 FindOptions 中指定关系:
const users = await dataSource.getRepository(User).find({
relations: {
profile: true,
},
})
或使用 QueryBuilder 进行关联查询:
const users = await dataSource
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.profile", "profile")
.getMany()
若在关系上启用预加载(eager loading),则无需在查询命令中显式指定关系——系统将自动加载。但使用 QueryBuilder 时预加载功能被禁用,必须通过 leftJoinAndSelect 手动加载关系。
关系可分为单向(unidirectional)和双向(bidirectional)。 单向关系仅在一方设置关系装饰器。 双向关系则在双方都设置关系装饰器。
前文创建的是单向关系,现将其改为双向:
import { Entity, PrimaryGeneratedColumn, Column, OneToOne } from "typeorm"
import { User } from "./User"
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number
@Column()
gender: string
@Column()
photo: string
@OneToOne(() => User, (user) => user.profile) // specify inverse side as a second parameter
user: User
}
import {
Entity,
PrimaryGeneratedColumn,
Column,
OneToOne,
JoinColumn,
} from "typeorm"
import { Profile } from "./Profile"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@OneToOne(() => Profile, (profile) => profile.user) // specify inverse side as a second parameter
@JoinColumn()
profile: Profile
}
现在已创建双向关系。注意:反向关系(inverse relation)不设置 @JoinColumn。
@JoinColumn 必须且只能设置在关系的一方——即持有外键的数据库表。
双向关系支持通过 QueryBuilder 从任意方进行关联查询:
const profiles = await dataSource
.getRepository(Profile)
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.user", "user")
.getMany()