|
|
@@ -32,7 +32,7 @@ export class YourEntityService extends GenericCrudService<YourEntity> {
|
|
|
| 方法 | 描述 | 参数 | 返回值 |
|
|
|
|------|------|------|--------|
|
|
|
| `getList` | 获取分页列表 | `page`, `pageSize`, `keyword`, `searchFields`, `where`, `relations`, `order` | `[T[], number]` |
|
|
|
-| `getById` | 根据ID获取单个实体 | `id: number` | `T \| null` |
|
|
|
+| `getById` | 根据ID获取单个实体 | `id: number`, `relations?: string[]` | `T \| null` |
|
|
|
| `create` | 创建实体 | `data: DeepPartial<T>` | `T` |
|
|
|
| `update` | 更新实体 | `id: number`, `data: Partial<T>` | `T \| null` |
|
|
|
| `delete` | 删除实体 | `id: number` | `boolean` |
|
|
|
@@ -73,6 +73,7 @@ const yourEntityRoutes = createCrudRoutes({
|
|
|
getSchema: YourEntitySchema,
|
|
|
listSchema: YourEntitySchema,
|
|
|
searchFields: ['name', 'description'], // 可选,指定搜索字段
|
|
|
+ relations: ['relatedEntity'], // 可选,指定关联查询关系(支持嵌套关联,如 ['relatedEntity.client'])
|
|
|
middleware: [authMiddleware] // 可选,添加中间件
|
|
|
});
|
|
|
|
|
|
@@ -89,7 +90,9 @@ export default yourEntityRoutes;
|
|
|
| `getSchema` | `z.ZodSchema` | 获取单个实体的响应 schema | 是 |
|
|
|
| `listSchema` | `z.ZodSchema` | 获取列表的响应 schema | 是 |
|
|
|
| `searchFields` | `string[]` | 搜索字段数组,用于关键词搜索 | 否 |
|
|
|
+| `relations` | `string[]` | 关联查询配置,指定需要关联查询的关系 | 否 |
|
|
|
| `middleware` | `any[]` | 应用于所有CRUD路由的中间件数组 | 否 |
|
|
|
+| `relationFields` | `RelationFieldOptions` | 多对多关联字段配置,支持通过ID数组操作关联关系 | 否 |
|
|
|
|
|
|
### 2.3 生成的路由
|
|
|
|
|
|
@@ -97,9 +100,9 @@ export default yourEntityRoutes;
|
|
|
|
|
|
| 方法 | 路径 | 描述 |
|
|
|
|------|------|------|
|
|
|
-| GET | `/` | 获取实体列表(支持分页、搜索、排序) |
|
|
|
+| GET | `/` | 获取实体列表(支持分页、搜索、排序、关联查询) |
|
|
|
| POST | `/` | 创建新实体 |
|
|
|
-| GET | `/{id}` | 获取单个实体详情 |
|
|
|
+| GET | `/{id}` | 获取单个实体详情(支持关联查询) |
|
|
|
| PUT | `/{id}` | 更新实体 |
|
|
|
| DELETE | `/{id}` | 删除实体 |
|
|
|
|
|
|
@@ -129,8 +132,9 @@ api.route('/api/v1/your-entities', yourEntityRoutes);
|
|
|
|
|
|
```typescript
|
|
|
// your-entity.entity.ts
|
|
|
-import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
|
|
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany } from 'typeorm';
|
|
|
import { z } from '@hono/zod-openapi';
|
|
|
+import { RelatedEntity } from './related-entity.entity';
|
|
|
|
|
|
@Entity('your_entity')
|
|
|
export class YourEntity {
|
|
|
@@ -140,6 +144,9 @@ export class YourEntity {
|
|
|
@Column({ name: 'name', type: 'varchar', length: 255 })
|
|
|
name!: string;
|
|
|
|
|
|
+ @ManyToOne(() => RelatedEntity, related => related.yourEntities)
|
|
|
+ relatedEntity!: RelatedEntity;
|
|
|
+
|
|
|
// 其他字段...
|
|
|
}
|
|
|
|
|
|
@@ -147,20 +154,113 @@ export class YourEntity {
|
|
|
export const YourEntitySchema = z.object({
|
|
|
id: z.number().int().positive().openapi({ description: '实体ID' }),
|
|
|
name: z.string().max(255).openapi({ description: '名称', example: '示例名称' }),
|
|
|
+ relatedEntity: RelatedEntitySchema, // 关联实体schema
|
|
|
// 其他字段schema...
|
|
|
});
|
|
|
|
|
|
export const CreateYourEntityDto = z.object({
|
|
|
name: z.string().max(255).openapi({ description: '名称', example: '示例名称' }),
|
|
|
+ relatedEntityId: z.number().int().positive().openapi({ description: '关联实体ID', example: 1 }),
|
|
|
// 其他创建字段schema...
|
|
|
});
|
|
|
|
|
|
export const UpdateYourEntityDto = z.object({
|
|
|
name: z.string().max(255).optional().openapi({ description: '名称', example: '示例名称' }),
|
|
|
+ relatedEntityId: z.number().int().positive().optional().openapi({ description: '关联实体ID', example: 1 }),
|
|
|
// 其他更新字段schema...
|
|
|
});
|
|
|
```
|
|
|
|
|
|
+### 2.5 多对多关联字段配置
|
|
|
+
|
|
|
+#### 2.5.1 关联字段配置 (RelationFieldOptions)
|
|
|
+
|
|
|
+新增 `relationFields` 配置选项,用于处理多对多关联字段:
|
|
|
+
|
|
|
+```typescript
|
|
|
+import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
|
|
|
+import { PolicyNews, PolicyNewsSchema, CreatePolicyNewsDto, UpdatePolicyNewsDto } from '@/server/modules/silver-users/policy-news.entity';
|
|
|
+import { File } from '@/server/modules/files/file.entity';
|
|
|
+import { authMiddleware } from '@/server/middleware/auth.middleware';
|
|
|
+
|
|
|
+const policyNewsRoutes = createCrudRoutes({
|
|
|
+ entity: PolicyNews,
|
|
|
+ createSchema: CreatePolicyNewsDto,
|
|
|
+ updateSchema: UpdatePolicyNewsDto,
|
|
|
+ getSchema: PolicyNewsSchema,
|
|
|
+ listSchema: PolicyNewsSchema,
|
|
|
+ relations: ['files'],
|
|
|
+ middleware: [authMiddleware],
|
|
|
+ relationFields: {
|
|
|
+ fileIds: {
|
|
|
+ relationName: 'files', // 实体中的关联属性名
|
|
|
+ targetEntity: File, // 关联的目标实体类
|
|
|
+ joinTableName: 'policy_news_files' // 可选:中间表名
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+#### 2.5.2 RelationFieldOptions 类型定义
|
|
|
+
|
|
|
+```typescript
|
|
|
+interface RelationFieldOptions {
|
|
|
+ [fieldName: string]: {
|
|
|
+ relationName: string; // 实体中的关联属性名
|
|
|
+ targetEntity: new () => any; // 关联的目标实体类
|
|
|
+ joinTableName?: string; // 中间表名(可选)
|
|
|
+ };
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 2.5.3 使用示例
|
|
|
+
|
|
|
+**实体定义:**
|
|
|
+```typescript
|
|
|
+@Entity('policy_news')
|
|
|
+export class PolicyNews {
|
|
|
+ @PrimaryGeneratedColumn({ unsigned: true })
|
|
|
+ id!: number;
|
|
|
+
|
|
|
+ @Column({ name: 'news_title', type: 'varchar', length: 255 })
|
|
|
+ newsTitle!: string;
|
|
|
+
|
|
|
+ // 关联文件的多对多关系
|
|
|
+ @ManyToMany(() => File)
|
|
|
+ @JoinTable({
|
|
|
+ name: 'policy_news_files',
|
|
|
+ joinColumn: { name: 'policy_news_id', referencedColumnName: 'id' },
|
|
|
+ inverseJoinColumn: { name: 'file_id', referencedColumnName: 'id' }
|
|
|
+ })
|
|
|
+ files?: File[];
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**请求格式:**
|
|
|
+```typescript
|
|
|
+// 创建政策资讯
|
|
|
+POST /api/v1/policy-news
|
|
|
+{
|
|
|
+ "newsTitle": "新政策解读",
|
|
|
+ "fileIds": [1, 2, 3] // 关联文件ID数组
|
|
|
+}
|
|
|
+
|
|
|
+// 更新政策资讯
|
|
|
+PUT /api/v1/policy-news/1
|
|
|
+{
|
|
|
+ "newsTitle": "更新后的政策解读",
|
|
|
+ "fileIds": [2, 4, 5] // 更新后的文件ID数组
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 2.5.4 特性说明
|
|
|
+
|
|
|
+- **自动处理**:系统会自动处理多对多关联的中间表操作
|
|
|
+- **事务安全**:所有关联操作都在事务中执行
|
|
|
+- **空数组支持**:传空数组 `[]` 表示清除所有关联
|
|
|
+- **向后兼容**:不影响现有实体的使用方式
|
|
|
+- **类型安全**:支持完整的TypeScript类型检查
|
|
|
+
|
|
|
## 4. 高级用法
|
|
|
|
|
|
### 4.1 自定义中间件
|
|
|
@@ -249,4 +349,5 @@ export class YourEntityService extends GenericCrudService<YourEntity> {
|
|
|
4. **数据验证**:确保Zod schema包含完整的验证规则和OpenAPI元数据
|
|
|
5. **搜索优化**:合理设置`searchFields`,避免在大表的文本字段上进行模糊搜索
|
|
|
6. **分页处理**:所有列表接口必须支持分页,避免返回大量数据
|
|
|
-7. **事务管理**:复杂操作应使用事务确保数据一致性
|
|
|
+7. **关联查询**:使用`relations`配置时,避免过度关联导致性能问题
|
|
|
+8. **事务管理**:复杂操作应使用事务确保数据一致性
|