关系
关系
关系可以帮助你轻松地与相关实体合作。有几种类型的关系:
你可以为关系指定几个选项:
eager: boolean
- 如果设置为true ,则在此实体上使用find *
或QueryBuilder
时,将始终使用主实体加载关系cascade: boolean
- 如果设置为true ,则将插入相关对象并在数据库中更新。onDelete: "RESTRICT"|"CASCADE"|"SET NULL"
- 指定删除引用对象时外键的行为方式primary: boolean
- 指示此关系的列是否为主列。nullable: boolean
- 指示此关系的列是否可为空。默认情况下是可空。
一对一
一对一是一种
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number;
@Column()
gender: string;
@Column()
photo: string;
}
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToOne(type => Profile)
@JoinColumn()
profile: Profile;
}
这里我们将
+-------------+--------------+----------------------------+
| profile |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| gender | varchar(255) | |
| photo | varchar(255) | |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| user |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
| profileId | int(11) | FOREIGN KEY |
+-------------+--------------+----------------------------+
同样,
const profile = new Profile();
profile.gender = "male";
profile.photo = "me.jpg";
await connection.manager.save(profile);
const user = new User();
user.name = "Joe Smith";
user.profile = profile;
await connection.manager.save(user);
启用级联后,只需一次save
调用即可保存此关系。要加载带有配置文件的用户,必须在FindOptions
中指定关系:
const userRepository = connection.getRepository(User);
const users = await userRepository.find({ relations: ["profile"] });
或者使用QueryBuilder
const users = await connection
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.profile", "profile")
.getMany();
通过在关系上启用预先加载,你不必指定关系或手动加入,它将始终自动加载。
双向关系
关系可以是单向的和双向的。单向是仅在一侧与关系装饰器的关系。双向是与关系两侧的装饰者的关系。我们刚刚创建了一个单向关系。让我们将它改为双向:
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number;
@Column()
gender: string;
@Column()
photo: string;
@OneToOne(
type => User,
user => user.profile
) // 将另一面指定为第二个参数
user: User;
}
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToOne(
type => Profile,
profile => profile.user
) // 指定另一面作为第二个参数
@JoinColumn()
profile: Profile;
}
我们只是创建了双向关系。注意,反向关系没有QueryBuilder
从双方加入关系:
const profiles = await connection
.getRepository(Profile)
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.user", "user")
.getMany();
多对一/ 一对多的关系
多对一
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column()
url: string;
@ManyToOne(
type => User,
user => user.photos
)
user: User;
}
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(
type => Photo,
photo => photo.user
)
photos: Photo[];
}
这里我们将
+-------------+--------------+----------------------------+
| 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
调用即可保存此关系。要在内部加载带有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();
通过在关系上启用预先加载,你不必指定关系或手动加入
多对多的关系
多对多是一种
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
}
@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
text: string;
@ManyToMany(type => Category)
@JoinTable()
categories: Category[];
}
+-------------+--------------+----------------------------+
| category |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| question |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| title | varchar(255) | |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| question_categories_category |
+-------------+--------------+----------------------------+
| questionId | int(11) | PRIMARY KEY FOREIGN KEY |
| categoryId | int(11) | PRIMARY KEY FOREIGN KEY |
+-------------+--------------+----------------------------+
如何保存这种关系:
const category1 = new Category();
category1.name = "animals";
await connection.manager.save(category1);
const category2 = new Category();
category2.name = "zoo";
await connection.manager.save(category2);
const question = new Question();
question.categories = [category1, category2];
await connection.manager.save(question);
启用级联后,只需一次save
调用即可保存此关系。要在FindOptions
中指定关系:
const questionRepository = connection.getRepository(Question);
const questions = await questionRepository.find({ relations: ["categories"] });
或者使用QueryBuilder
const questions = await connection
.getRepository(Question)
.createQueryBuilder("question")
.leftJoinAndSelect("question.categories", "category")
.getMany();
通过在关系上启用预先加载,你不必指定关系或手动加入,它将始终自动加载。
双向关系
关系可以是单向的和双向的。单向是仅在一侧与关系装饰器的关系。双向是与关系两侧的装饰者的关系。我们刚刚创建了一个单向关系。让我们改为双向:
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany(
type => Question,
question => question.categories
)
questions: Question[];
}
@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
text: string;
@ManyToMany(
type => Category,
category => category.questions
)
@JoinTable()
categories: Category[];
}
我们只是创建了双向关系。注意,反向关系没有 @JoinTable
,@JoinTable
必须只在关系的一边。双向关系允许您使用 QueryBuilder
从双方加入关系:
const categoriesWithQuestions = await connection
.getRepository(Category)
.createQueryBuilder("category")
.leftJoinAndSelect("category.questions", "question")
.getMany();
Eager 和Lazy 关系
Eager 关系
每次从数据库加载实体时,都会自动加载
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany(
type => Question,
question => question.categories
)
questions: Question[];
}
@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
text: string;
@ManyToMany(
type => Category,
category => category.questions,
{
eager: true
}
)
@JoinTable()
categories: Category[];
}
现在当你加载
const questionRepository = connection.getRepository(Question);
// questions 将加载其类别 categories
const questions = await questionRepository.find();
find *
方法时才有效。如果你使用QueryBuilder
,则禁用leftJoinAndSelect
来加载。eager:true
是不允许的。
Lazy 关系
当你访问的时候会加载Promise
作为类型,并且将值存储在一个
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany(
type => Question,
question => question.categories
)
questions: Promise<Question[]>;
}
@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
text: string;
@ManyToMany(
type => Category,
category => category.questions
)
@JoinTable()
categories: Promise<Category[]>;
}
categories
是一个
例如:
保存这种关系:
const category1 = new Category();
category1.name = "animals";
await connection.manager.save(category1);
const category2 = new Category();
category2.name = "zoo";
await connection.manager.save(category2);
const question = new Question();
question.categories = Promise.resolve([category1, category2]);
await connection.manager.save(question);
如何在
const question = await connection.getRepository(Question).findOne(1);
const categories = await question.categories;
// you'll have all question's categories inside "categories" variable now
注意:如果你来自其他语言(Java,