基础关联关系
IBest ORM 提供了完整的关联关系支持,包括一对一、一对多、多对一和多对多关联。通过装饰器注解,您可以轻松定义实体之间的关联关系。
关联类型概览
关联类型 | 装饰器 | 描述 | 示例 |
---|---|---|---|
一对一 | @HasOne | 一个实体拥有另一个实体 | 用户 → 用户资料 |
一对多 | @HasMany | 一个实体拥有多个子实体 | 用户 → 订单列表 |
多对一 | @BelongsTo | 多个实体属于一个父实体 | 订单 → 用户 |
多对多 | @ManyToMany | 多个实体关联多个实体 | 用户 ↔ 角色 |
一对一关联 (@HasOne)
一对一关联表示一个实体拥有另一个实体的单个实例。
typescript
import { Table, Field, FieldType, HasOne } from '@ibestservices/ibest-orm';
@Table({ name: 'users' })
export class User {
@Field({ type: FieldType.INTEGER, tag: ['primaryKey', 'autoIncrement'] })
id: number;
@Field({ type: FieldType.TEXT, tag: ['notNull'] })
name: string;
@Field({ type: FieldType.TEXT })
email: string;
// 一对一关联:用户拥有一个用户资料
@HasOne({
target: () => UserProfile,
foreignKey: 'user_id',
cascade: [CascadeType.All]
})
profile: UserProfile;
}
@Table({ name: 'user_profiles' })
export class UserProfile {
@Field({ type: FieldType.INTEGER, tag: ['primaryKey', 'autoIncrement'] })
id: number;
@Field({ type: FieldType.INTEGER, tag: ['notNull'] })
user_id: number;
@Field({ type: FieldType.TEXT })
bio: string;
@Field({ type: FieldType.TEXT })
avatar: string;
// 反向关联:用户资料属于一个用户
@BelongsTo({
target: () => User,
foreignKey: 'user_id'
})
user: User;
}
一对多关联 (@HasMany)
一对多关联表示一个实体拥有多个子实体。
typescript
@Table({ name: 'users' })
export class User {
@Field({ type: FieldType.INTEGER, tag: ['primaryKey', 'autoIncrement'] })
id: number;
@Field({ type: FieldType.TEXT, tag: ['notNull'] })
name: string;
// 一对多关联:用户拥有多个订单
@HasMany({
target: () => Order,
foreignKey: 'user_id',
cascade: [CascadeType.Create, CascadeType.Update]
})
orders: Order[];
}
@Table({ name: 'orders' })
export class Order {
@Field({ type: FieldType.INTEGER, tag: ['primaryKey', 'autoIncrement'] })
id: number;
@Field({ type: FieldType.INTEGER, tag: ['notNull'] })
user_id: number;
@Field({ type: FieldType.TEXT, tag: ['notNull'] })
product_name: string;
@Field({ type: FieldType.REAL })
amount: number;
// 反向关联:订单属于一个用户
@BelongsTo({
target: () => User,
foreignKey: 'user_id'
})
user: User;
// 嵌套一对多关联:订单拥有多个订单项
@HasMany({
target: () => OrderItem,
foreignKey: 'order_id',
cascade: [CascadeType.All]
})
items: OrderItem[];
}
多对多关联 (@ManyToMany)
多对多关联通过中间表连接两个实体,每个实体可以关联多个另一个实体的实例。
typescript
@Table({ name: 'users' })
export class User {
@Field({ type: FieldType.INTEGER, tag: ['primaryKey', 'autoIncrement'] })
id: number;
@Field({ type: FieldType.TEXT, tag: ['notNull'] })
name: string;
// 多对多关联:用户拥有多个角色
@ManyToMany({
target: () => Role,
through: 'user_roles', // 中间表名
throughForeignKey: 'user_id', // 当前实体在中间表的外键
throughOtherKey: 'role_id', // 目标实体在中间表的外键
cascade: [CascadeType.Create, CascadeType.Update]
})
roles: Role[];
}
@Table({ name: 'roles' })
export class Role {
@Field({ type: FieldType.INTEGER, tag: ['primaryKey', 'autoIncrement'] })
id: number;
@Field({ type: FieldType.TEXT, tag: ['notNull'] })
name: string;
@Field({ type: FieldType.TEXT })
description: string;
// 反向多对多关联:角色属于多个用户
@ManyToMany({
target: () => User,
through: 'user_roles',
throughForeignKey: 'role_id',
throughOtherKey: 'user_id'
})
users: User[];
}
关联配置选项
基础配置
选项 | 类型 | 描述 | 必需 |
---|---|---|---|
target | () => Class | 目标实体类 | ✓ |
foreignKey | string | 外键字段名 | ✓ |
localKey | string | 本地键字段名 | ✗ |
cascade | CascadeType[] | 级联操作类型 | ✗ |
多对多特有配置
选项 | 类型 | 描述 | 必需 |
---|---|---|---|
through | string | 中间表名 | ✓ |
throughForeignKey | string | 当前实体在中间表的外键 | ✓ |
throughOtherKey | string | 目标实体在中间表的外键 | ✓ |
级联操作类型
typescript
export enum CascadeType {
Create = 'create', // 级联创建
Update = 'update', // 级联更新
Delete = 'delete', // 级联删除
All = 'all' // 所有级联操作
}
使用示例
创建带关联的实体
typescript
const user = new User();
user.name = 'John Doe';
user.email = 'john@example.com';
// 创建关联的用户资料
user.profile = new UserProfile();
user.profile.bio = 'Software Developer';
user.profile.avatar = 'avatar.jpg';
// 创建关联的订单
user.orders = [
{
product_name: 'Laptop',
amount: 1299.99,
items: [
{ product_name: 'Laptop', quantity: 1, price: 1299.99 }
]
}
];
// 创建关联的角色
user.roles = [
{ name: 'user', description: 'Regular User' },
{ name: 'developer', description: 'Software Developer' }
];
// 级联创建(会自动创建所有关联实体)
const result = await orm.Create(user, { cascade: true });
查询带关联的实体
typescript
// 预加载关联数据
const userWithRelations = await orm.Session(User)
.With(['profile', 'orders.items', 'roles'])
.Where('email', 'john@example.com')
.FirstWithRelations();
console.log(userWithRelations.profile.bio);
console.log(userWithRelations.orders[0].items);
console.log(userWithRelations.roles);
注意事项
- 外键约束:确保数据库表结构与关联配置一致
- 循环引用:避免在关联定义中产生循环引用
- 性能考虑:合理使用预加载和延迟加载
- 级联操作:谨慎使用级联删除,避免意外删除数据
- 中间表:多对多关联的中间表会自动创建和管理