user-实体用户关联开发.md 5.9 KB


description: "实体现有字段与用户实体关联开发指令"

适用场景

当实体中已经存在用户相关的字段(如 handlerId, createdBy, userId, operatorId 等),需要将这些字段与 User 实体建立关联关系时使用。

开发步骤

1. 修改实体定义

找到实体文件 src/server/modules/[模块名]/[实体名].entity.ts,将现有用户字段改为关联关系:

1.1 替换字段类型和装饰器

// 修改前:原始字段定义
@Column({ name: 'handler_id', type: 'int', comment: '处理人ID' })
handlerId!: number;

// 修改后:单向关联关系定义
@ManyToOne(() => User)
@JoinColumn({ name: 'handler_id' })
handler!: User;

// 如果允许为空(单向关联)
@ManyToOne(() => User, { nullable: true })
@JoinColumn({ name: 'handler_id' })
handler?: User | null;

1.2 添加User实体导入

// 在实体顶部添加
import { User } from '@/server/modules/users/user.entity';

1.3 在User实体中添加反向关联(可选)

如果需要双向关联,在User实体中添加对应的关系定义:

// 在User实体中添加对应的关系定义(双向关联)
@OneToMany(() => AlertHandleLog, log => log.handler)
alertHandleLogs?: AlertHandleLog[];

注意:单向关联不需要此步骤,保持现有配置即可

2. 更新Zod Schema

在对应的 schema 文件中同步修改:

2.1 修改实体Schema

// 在文件顶部添加导入
import { UserSchema } from '@/server/modules/users/user.schema';

// 修改前
handlerId: z.number().int().positive().openapi({
  description: '处理人ID',
  example: 1
})

// 修改后 - 使用导入的UserSchema
handler: UserSchema.omit({ password: true }).nullable().optional().openapi({
  description: '处理人信息'
})

2.2 修改Create/Update DTO

// 修改前:Create DTO
export const CreateAlertHandleLogDto = z.object({
  handlerId: z.number().int().positive().openapi({
    description: '处理人ID',
    example: 1
  }),
  // ... 其他字段
});

// 修改后:Create DTO
export const CreateAlertHandleLogDto = z.object({
  handlerId: z.number().int().positive().openapi({
    description: '处理人ID',
    example: 1
  }),
  // ... 其他字段
});

// Update DTO保持不变,但handlerId改为optional
export const UpdateAlertHandleLogDto = z.object({
  handlerId: z.number().int().positive().optional().openapi({
    description: '处理人ID',
    example: 1
  }),
  // ... 其他字段
});

4. 更新通用CRUD配置

如果使用通用CRUD路由,需要配置relations:

const routes = createCrudRoutes({
  entity: AlertHandleLog,
  createSchema: CreateAlertHandleLogDto,
  updateSchema: UpdateAlertHandleLogDto,
  getSchema: AlertHandleLogSchema,
  listSchema: AlertHandleLogSchema,
  relations: ['handler'], // 添加关联配置
  middleware: [authMiddleware]
});

命名规范

类型 命名格式 示例 说明
数据库字段 {前缀}_id handler_id 保持原有字段名不变
实体字段 {前缀} handler 关联实体对象
反向关联 {实体名}s alertHandleLogs User实体中的集合名
外键字段 {前缀}Id handlerId DTO中的外键字段

完整示例

实体类 (src/server/modules/alerts/alert-handle-log.entity.ts)

import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
import { User } from '@/server/modules/users/user.entity';

@Entity('alert_handle_logs')
export class AlertHandleLog {
  @PrimaryGeneratedColumn({ unsigned: true })
  id!: number;

  @Column({ name: 'handler_id', type: 'int', comment: '处理人ID' })
  handlerId!: number;

  // 单向关联定义(无需反向引用)
  @ManyToOne(() => User)
  @JoinColumn({ name: 'handler_id' })
  handler!: User;

  // ... 其他字段
}

User实体反向关联(可选,仅双向关联需要)

如果需要双向关联,在User实体中添加:

@OneToMany(() => AlertHandleLog, log => log.handler)
alertHandleLogs?: AlertHandleLog[];

单向关联说明:当前配置为单向关联,无需在User实体中添加反向关系定义

Schema定义 (src/server/modules/alerts/alert-handle-log.schema.ts)

// 引入用户Schema
import { UserSchema } from '@/server/modules/users/user.schema';

// 响应Schema - 使用UserSchema.omit去掉敏感字段
handler: UserSchema.omit({ password: true }).nullable().optional().openapi({
  description: '处理人信息'
}),

// 请求DTO中的外键字段
handlerId: z.number().int().positive().openapi({
  description: '处理人ID',
  example: 1
})

注意事项

  1. 数据库兼容性:现有数据库字段保持不变,只是从整数字段升级为外键约束
  2. API兼容性:DTO中的外键字段名保持不变(如handlerId),确保API接口兼容
  3. 查询性能:配置relations后,关联查询会自动优化,避免N+1问题
  4. 级联操作:默认不级联删除,删除用户不会影响关联记录
  5. 空值处理:如果handlerId为null,handler关联对象将为null

常见问题

Q: 如何支持多个用户关联字段?

A: 重复上述步骤,为每个用户字段建立独立的关联关系,例如:

@ManyToOne(() => User, user => user.createdAlerts)
@JoinColumn({ name: 'created_by' })
creator!: User;

@ManyToOne(() => User, user => user.updatedAlerts)
@JoinColumn({ name: 'updated_by' })
updater?: User | null;

Q: 如何处理复合用户关联?

A: 使用相同的方法,只是字段名不同:

@ManyToOne(() => User, user => user.assignedTasks)
@JoinColumn({ name: 'assignee_id' })
assignee!: User;