---
description: "实体与文件关联开发指令 - 指导如何在实体中添加文件关联字段"
---

# 实体与文件关联开发指令

## 概述
本指令指导如何在实体中添加与文件管理系统的关联关系，基于用户实体(UserEntity)的最佳实践。

## 文件关联标准实现

### 1. 实体定义规范

在实体类中添加文件关联字段：

```typescript
// 1. 导入文件实体
import { File } from '@/server/modules/files/file.entity';

// 2. 在实体类中添加字段
@Column({ 
  name: '{field_prefix}_file_id', 
  type: 'int', 
  unsigned: true, 
  nullable: true, 
  comment: '{描述}文件ID' 
})
{fieldPrefix}FileId!: number | null;

@ManyToOne(() => File, { nullable: true })
@JoinColumn({ 
  name: '{field_prefix}_file_id', 
  referencedColumnName: 'id' 
})
{fieldPrefix}File!: File | null;
```

### 2. Schema定义规范

在实体的schema文件中添加文件关联字段：

```typescript
// 基础字段定义
{fieldPrefix}FileId: z.number()
  .int()
  .positive()
  .nullable()
  .openapi({
    example: 1,
    description: '{描述}文件ID'
  }),

// 关联文件对象（用于响应）
{fieldPrefix}File: z.object({
  id: z.number().int().positive().openapi({ description: '文件ID' }),
  name: z.string().max(255).openapi({ description: '文件名', example: 'example.jpg' }),
  fullUrl: z.string().openapi({ description: '文件完整URL', example: 'https://example.com/file.jpg' }),
  type: z.string().nullable().openapi({ description: '文件类型', example: 'image/jpeg' }),
  size: z.number().nullable().openapi({ description: '文件大小(字节)', example: 102400 })
}).nullable().optional().openapi({
  description: '{描述}文件信息'
}),
```

### 3. 命名规范

| 类型 | 命名格式 | 示例 |
|------|----------|------|
| 数据库字段 | `{前缀}_file_id` | `avatar_file_id` |
| 实体字段 | `{前缀}FileId` | `fileId` |
| 关联实体 | `{前缀}File` | `file` |
| 描述注释 | `{描述}文件ID` | `头像文件ID` |

### 4. 完整示例 - 基于用户实体

**实体类** ([`src/server/modules/users/user.entity.ts`](src/server/modules/users/user.entity.ts:29-34)):
```typescript
@Column({ name: 'avatar_file_id', type: 'int', unsigned: true, nullable: true, comment: '头像文件ID' })
fileId!: number | null;

@ManyToOne(() => File, { nullable: true })
@JoinColumn({ name: 'avatar_file_id', referencedColumnName: 'id' })
file!: File | null;
```

**Schema定义** ([`src/server/modules/users/user.schema.ts`](src/server/modules/users/user.schema.ts:33-45)):
```typescript
fileId: z.number().int().positive().nullable().openapi({
  example: 1,
  description: '头像文件ID'
}),
file: z.object({
  id: z.number().int().positive().openapi({ description: '文件ID' }),
  name: z.string().max(255).openapi({ description: '文件名', example: 'avatar.jpg' }),
  fullUrl: z.string().openapi({ description: '文件完整URL', example: 'https://example.com/avatar.jpg' }),
  type: z.string().nullable().openapi({ description: '文件类型', example: 'image/jpeg' }),
  size: z.number().nullable().openapi({ description: '文件大小(字节)', example: 102400 })
}).nullable().optional().openapi({
  description: '头像文件信息'
}),
```

## 使用步骤

### 步骤1: 添加实体字段
1. 在实体类中添加 `{prefix}FileId` 和 `{prefix}File` 字段
2. 使用 `@ManyToOne` 关联 `File` 实体
3. 配置 `@JoinColumn` 指定外键字段名

### 步骤2: 添加Schema定义
1. 在 `Create{Entity}Dto` 中添加 `{prefix}FileId` 字段
2. 在 `Update{Entity}Dto` 中添加可选的 `{prefix}FileId` 字段
3. 在实体Schema中添加 `{prefix}File` 对象用于响应

### 步骤3: 数据库迁移
确保数据库表包含 `{prefix}_file_id` 字段，类型为 INT UNSIGNED NULL

## 使用场景

### 场景1: 单文件关联
适用于实体只需要关联单个文件的情况，如：
- 用户头像
- 商品封面图
- 文档附件

### 场景2: 多文件关联
如需关联多个文件，请使用 ManyToMany 关联，参考广告实体的实现。

### 场景3: 通用CRUD路由配置
对于使用通用CRUD路由的实体，需要配置 `relations` 以自动关联查询文件信息：

```typescript
// 示例：广告实体的通用CRUD配置
import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
import { Advertisement } from '@/server/modules/advertisements/advertisement.entity';
import { AdvertisementSchema, CreateAdvertisementDto, UpdateAdvertisementDto } from '@/server/modules/advertisements/advertisement.schema';
import { authMiddleware } from '@/server/middleware/auth.middleware';

const advertisementRoutes = createCrudRoutes({
  entity: Advertisement,
  createSchema: CreateAdvertisementDto,
  updateSchema: UpdateAdvertisementDto,
  getSchema: AdvertisementSchema,
  listSchema: AdvertisementSchema,
  searchFields: ['title', 'code'],
  relations: ['imageFile'], // 关键配置：自动关联查询图片文件
  middleware: [authMiddleware]
});
```

## 注意事项

1. **空值处理**: 字段必须支持 `null`，允许无文件关联
2. **级联操作**: 默认不级联，删除文件不会影响关联实体
3. **文件验证**: 前端需先上传文件获取文件ID，再进行实体关联
4. **类型安全**: 确保所有字段类型定义一致（number | null）
5. **关联查询**: 配置 `relations` 后，通用CRUD会自动处理关联查询

## 扩展说明

此标准基于用户实体的头像文件关联实现，适用于项目中所有需要文件关联的实体。后续实体按此标准实现即可保持统一性。