file-实体文件关联开发指南.md 5.5 KB


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

实体与文件关联开发指令

概述

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

文件关联标准实现

1. 实体定义规范

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

// 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文件中添加文件关联字段:

// 基础字段定义
{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):

@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):

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 以自动关联查询文件信息:

// 示例:广告实体的通用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会自动处理关联查询

扩展说明

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