Has Many 关联
介绍
Has Many 关联表示一个模型拥有另一个模型的多个实例。这是一种一对多的关联关系,常用于表示父子关系或分类关系。
定义 Has Many 关联
使用 @HasMany 装饰器来定义一对多关联:
ts
import { Table, Column, PrimaryKey, HasMany, BelongsTo, ColumnType } from '@ibestservices/ibest-orm';
@Table()
class User {
@PrimaryKey()
id?: number;
@Column()
name!: string;
@Column()
email?: string;
// 一对多关联:一个用户有多篇文章
@HasMany(() => Article, { foreignKey: 'user_id' })
articles?: Article[];
}
@Table()
class Article {
@PrimaryKey()
id?: number;
@Column()
title!: string;
@Column()
content?: string;
@Column({ name: 'user_id', type: ColumnType.INTEGER })
userId?: number;
// 多对一关联:文章属于一个用户
@BelongsTo(() => User, { foreignKey: 'userId' })
author?: User;
}配置参数
target(第一个参数)
- 类型:
() => Class或Class - 描述: 目标模型类或返回目标模型类的工厂函数
- 必需: 是
- 示例:
() => Article
options(第二个参数)
foreignKey
- 类型:
string - 描述: 目标表中的外键字段名
- 默认值:
${当前表名}_id(自动推断) - 示例:
'user_id'
localKey
- 类型:
string - 描述: 当前表中的本地键字段名(通常是主键)
- 默认值:
'id'
cascade
- 类型:
CascadeType[] - 描述: 级联操作类型
- 可选值:
[CascadeType.Delete] - 示例: 删除用户时自动删除其所有文章
lazy
- 类型:
boolean - 描述: 是否延迟加载
- 默认值:
true
查询 Has Many 关联
预加载关联数据
ts
import { getORM } from '@ibestservices/ibest-orm';
const orm = getORM();
// 查询用户及其所有文章
const users = orm.query(User)
.with('articles')
.find();
console.log('用户及文章:', users);
// 输出:
// [
// {
// id: 1,
// name: "张三",
// email: "zhangsan@example.com",
// articles: [
// { id: 1, title: "TypeScript入门指南", userId: 1 },
// { id: 2, title: "React最佳实践", userId: 1 }
// ]
// }
// ]查询单个用户的文章
ts
// 查询指定用户及其文章
const user = orm.query(User)
.with('articles')
.where({ id: 1 })
.first();
console.log(`用户 ${user?.name} 共有 ${user?.articles?.length || 0} 篇文章`);嵌套预加载
ts
// 查询用户、文章及文章的评论(需要 Article 定义 comments 关联)
const users = orm.query(User)
.with('articles.comments')
.find();完整示例
ts
import {
Table, Column, PrimaryKey, HasMany, BelongsTo,
initORMWithMemory, getORM, ColumnType
} from '@ibestservices/ibest-orm';
// 定义模型
@Table()
class Author {
@PrimaryKey()
id?: number;
@Column()
name!: string;
@HasMany(() => Book, { foreignKey: 'author_id' })
books?: Book[];
}
@Table()
class Book {
@PrimaryKey()
id?: number;
@Column()
title!: string;
@Column({ name: 'author_id', type: ColumnType.INTEGER })
authorId?: number;
@BelongsTo(() => Author, { foreignKey: 'authorId' })
author?: Author;
}
// 初始化
const orm = initORMWithMemory();
orm.migrate(Author, Book);
// 创建数据
const author = new Author();
author.name = '鲁迅';
const authorId = orm.insert(author);
const book1 = new Book();
book1.title = '呐喊';
book1.authorId = authorId;
orm.insert(book1);
const book2 = new Book();
book2.title = '彷徨';
book2.authorId = authorId;
orm.insert(book2);
// 查询作者及其书籍
const authors = orm.query(Author).with('books').find();
console.log(authors[0]?.books); // [{ title: '呐喊' }, { title: '彷徨' }]
// 查询书籍及其作者
const books = orm.query(Book).with('author').find();
console.log(books[0]?.author?.name); // '鲁迅'注意事项
提示
- Has Many 关联返回数组,即使没有关联数据也会返回空数组
[] - 预加载查询会执行两次 SQL:先查主表,再查关联表
- 使用级联删除时要谨慎,确保业务逻辑正确
注意
- 大量关联数据可能影响查询性能
- 删除主记录前要考虑关联数据的处理策略
- 外键字段名需要与数据库列名一致(使用 snake_case)