Prechádzať zdrojové kódy

✨ feat(crud): 增强CRUD功能的关联查询支持

- 在列表查询中使用relations参数配置关联查询
- 在单条查询中添加relations参数支持关联查询
- 优化getById方法,支持通过relations参数指定关联关系

♻️ refactor(crud): 代码格式与注释优化

- 统一代码中的空行格式
- 更新注释描述,使"关联查询"表述更准确
- 调整createQueryBuilder方法位置,优化代码结构
yourname 8 mesiacov pred
rodič
commit
4ccdc6be54

+ 2 - 2
src/server/utils/generic-crud.routes.ts

@@ -233,7 +233,7 @@ export function createCrudRoutes<
           keyword,
           searchFields,
           undefined, // where条件
-          [], // relations
+          relations || [], // 关联查询配置
           order
         );
         
@@ -269,7 +269,7 @@ export function createCrudRoutes<
     .openapi(getRouteDef, async (c) => {
       try {
         const { id } = c.req.valid('param');
-        const result = await crudService.getById(id);
+        const result = await crudService.getById(id, relations || []);
         
         if (!result) {
           return c.json({ code: 404, message: '资源不存在' }, 404);

+ 19 - 19
src/server/utils/generic-crud.service.ts

@@ -3,7 +3,7 @@ import { z } from '@hono/zod-openapi';
 
 export abstract class GenericCrudService<T extends ObjectLiteral> {
   protected repository: Repository<T>;
-  
+
   constructor(
     protected dataSource: DataSource,
     protected entity: new () => T
@@ -14,9 +14,6 @@ export abstract class GenericCrudService<T extends ObjectLiteral> {
   /**
    * 获取分页列表
    */
-  /**
-   * 获取分页列表,支持高级查询
-   */
   async getList(
     page: number = 1,
     pageSize: number = 10,
@@ -28,21 +25,21 @@ export abstract class GenericCrudService<T extends ObjectLiteral> {
   ): Promise<[T[], number]> {
     const skip = (page - 1) * pageSize;
     const query = this.repository.createQueryBuilder('entity');
-    
-    // 关联查询
+
+    // 添加关联关系
     if (relations.length > 0) {
       relations.forEach(relation => {
         query.leftJoinAndSelect(`entity.${relation}`, relation);
       });
     }
-    
+
     // 关键词搜索
     if (keyword && searchFields && searchFields.length > 0) {
       query.andWhere(searchFields.map(field => `entity.${field} LIKE :keyword`).join(' OR '), {
         keyword: `%${keyword}%`
       });
     }
-    
+
     // 条件查询
     if (where) {
       Object.entries(where).forEach(([key, value]) => {
@@ -51,27 +48,23 @@ export abstract class GenericCrudService<T extends ObjectLiteral> {
         }
       });
     }
-    
+
     // 排序
     Object.entries(order).forEach(([key, direction]) => {
       query.orderBy(`entity.${key}`, direction);
     });
-    
-    return query.skip(skip).take(pageSize).getManyAndCount();
-  }
 
-  /**
-   * 高级查询方法
-   */
-  createQueryBuilder(alias: string = 'entity') {
-    return this.repository.createQueryBuilder(alias);
+    return query.skip(skip).take(pageSize).getManyAndCount();
   }
 
   /**
    * 根据ID获取单个实体
    */
-  async getById(id: number): Promise<T | null> {
-    return this.repository.findOneBy({ id } as any);
+  async getById(id: number, relations: string[] = []): Promise<T | null> {
+    return this.repository.findOne({
+      where: { id } as any,
+      relations
+    });
   }
 
   /**
@@ -97,6 +90,13 @@ export abstract class GenericCrudService<T extends ObjectLiteral> {
     const result = await this.repository.delete(id);
     return result.affected === 1;
   }
+
+  /**
+   * 高级查询方法
+   */
+  createQueryBuilder(alias: string = 'entity') {
+    return this.repository.createQueryBuilder(alias);
+  }
 }
 
 export type CrudOptions<