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


## 适用场景

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

## 开发步骤

### 1. 修改实体定义

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

#### 1.1 替换字段类型和装饰器

```typescript
// 修改前：原始字段定义
@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实体导入

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

#### 1.3 在User实体中添加反向关联（可选）

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

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

> **注意**：单向关联不需要此步骤，保持现有配置即可

### 2. 更新Zod Schema

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

#### 2.1 修改实体Schema

```typescript
// 在文件顶部添加导入
import { UserSchema } from '@d8d/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

```typescript
// 修改前：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：

```typescript
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`](src/server/modules/alerts/alert-handle-log.entity.ts))

```typescript
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
import { User } from '@d8d/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实体中添加：

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

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

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

```typescript
// 引入用户Schema
import { UserSchema } from '@d8d/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: 重复上述步骤，为每个用户字段建立独立的关联关系，例如：
```typescript
@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: 使用相同的方法，只是字段名不同：
```typescript
@ManyToOne(() => User, user => user.assignedTasks)
@JoinColumn({ name: 'assignee_id' })
assignee!: User;
```