Skip to content

基础关联关系

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目标实体类
foreignKeystring外键字段名
localKeystring本地键字段名
cascadeCascadeType[]级联操作类型

多对多特有配置

选项类型描述必需
throughstring中间表名
throughForeignKeystring当前实体在中间表的外键
throughOtherKeystring目标实体在中间表的外键

级联操作类型

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);

注意事项

  1. 外键约束:确保数据库表结构与关联配置一致
  2. 循环引用:避免在关联定义中产生循环引用
  3. 性能考虑:合理使用预加载和延迟加载
  4. 级联操作:谨慎使用级联删除,避免意外删除数据
  5. 中间表:多对多关联的中间表会自动创建和管理