OneToMany 和 ManyToOne
在使用 ORM(如 TypeORM)进行实体关系设计时,@OneToMany
和 @ManyToOne
是非常重要的注解,常用来表示两个实体之间的一对多关系。下面通过例子详细说明它们的使用场景和工作方式。
@OneToMany
和 @ManyToOne
的基本概念
-
@ManyToOne
表示 “多” 的一方指向 “一” 的一方。它总是定义在关系的 “多” 一侧。- 数据库中通常对应一个外键列。
- 该装饰器是关系的拥有方,负责维护外键。
-
@OneToMany
表示 “一” 的一方指向 “多” 的一方。它总是定义在关系的 “一” 一侧。- 数据库中没有直接对应的列,而是反向映射。
- 必须与
@ManyToOne
配合使用,不能单独存在。
示例:用户与文章的关系
场景:
- 一个用户可以拥有多篇文章。
- 每篇文章属于一个用户。
1. 实体设计
User
实体
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Article } from './article.entity';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
// 一个用户拥有多篇文章
@OneToMany(() => Article, (article) => article.author)
articles: Article[];
}
Article
实体
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { User } from './user.entity';
@Entity()
export class Article {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@ManyToOne(() => User, (user) => user.articles, { onDelete: 'CASCADE' })
author: User; // 每篇文章属于一个用户
}
2. 数据库结构
根据上述实体,TypeORM 将生成以下表结构:
User
表
id | name |
---|---|
1 | Alice |
2 | Bob |
Article
表
id | title | authorId |
---|---|---|
1 | First Post | 1 |
2 | Second Post | 1 |
3 | Third Post | 2 |
3. 插入数据
创建用户和文章
const userRepository = dataSource.getRepository(User);
const articleRepository = dataSource.getRepository(Article);
// 创建用户
const user = userRepository.create({ name: 'Alice' });
await userRepository.save(user);
// 创建文章
const article1 = articleRepository.create({ title: 'First Post', author: user });
const article2 = articleRepository.create({ title: 'Second Post', author: user });
await articleRepository.save([article1, article2]);
4. 查询数据
查询用户的文章
const userWithArticles = await userRepository.findOne({
where: { id: 1 },
relations: ['articles'],
});
console.log(userWithArticles);
输出:
{
"id": 1,
"name": "Alice",
"articles": [
{ "id": 1, "title": "First Post" },
{ "id": 2, "title": "Second Post" }
]
}
查询文章及其作者
const articleWithAuthor = await articleRepository.findOne({
where: { id: 1 },
relations: ['author'],
});
console.log(articleWithAuthor);
输出:
{
"id": 1,
"title": "First Post",
"author": { "id": 1, "name": "Alice" }
}
关键点总结
-
@ManyToOne
是外键的维护者:- 它在数据库中定义外键列(如
authorId
)。 - 用于指向关系的 “一” 侧。
- 它在数据库中定义外键列(如
-
@OneToMany
是关系的反向映射:- 它没有单独的数据库列。
- 它仅用作
@ManyToOne
的反向映射,表示 “一” 侧可以访问所有 “多” 侧的记录。
-
relations
必须手动加载:- TypeORM 默认不会加载关联字段,需在查询时指定
relations
。
- TypeORM 默认不会加载关联字段,需在查询时指定
-
cascade
选项:cascade: true
允许保存或删除时级联操作(如在保存用户时自动保存其文章)。