You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeORM报错InsertQueryBuilderCls不是构造函数的排查与解决

TypeORM事务中出现InsertQueryBuilderCls构造函数错误的排查与解决

问题场景

通过EntityManager执行事务操作,目的是设置search_path并调用存储过程(确保无嵌套提交),代码实现如下:

async savetournamentTransaction(tournament: any, matchId: string) {
    await this.connection.manager.transaction(async (tournamentEntityManager) => {
      const tournamentRepository = tournamentEntityManager.getRepository(tournament);
      await tournamentRepository.query(`SET LOCAL search_path to ${matchId}`);
      await tournamentRepository.save(tournament);
      await tournamentRepository.query(
        `CALL fillOrganizationScheduleTable($1,${tournament.tournament_id});`,
        [matchId],
      );
    });
  }
}

执行后抛出错误:

[Nest] 790  - 09/16/2022, 4:40:43 PM   ERROR [ExceptionsHandler] InsertQueryBuilderCls is not a constructor
TypeError: InsertQueryBuilderCls is not a constructor
    at SelectQueryBuilder.insert (/mypath/desktop/prj/volleyball-organization/src/query-builder/QueryBuilder.ts:200:16)
    at SubjectExecutor.executeInsertOperations (/mypath/desktop/prj/volleyball-organization/src/persistence/SubjectExecutor.ts:430:26)
    at SubjectExecutor.execute (/mypath/desktop/prj/volleyball-organization/src/persistence/SubjectExecutor.ts:137:20)
    at EntityPersistExecutor.execute (/mypath/desktop/prj/volleyball-organization/src/persistence/EntityPersistExecutor.ts:194:36)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at /mypath/desktop/prj/volleyball-organization/src/tournaments/tournaments.service.ts:155:13
    at EntityManager.transaction (/mypath/desktop/prj/volleyball-organization/src/entity-manager/EntityManager.ts:151:28)
    at tournamentsService.savetournamentTransaction (/mypath/desktop/prj/volleyball-organization/src/tournaments/tournaments.service.ts:152:9)
    at tournamentsService.createtournament (/mypath/desktop/prj/volleyball-organization/src/tournaments/tournaments.service.ts:113:9)
    at /mypath/desktop/prj/volleyball-organization/node_modules/@nestjs/core/router/router-execution-context.js:46:28  

错误原因

核心问题出在tournamentEntityManager.getRepository(tournament)这一行:

  • TypeORM的getRepository方法要求传入实体类(比如定义的Tournament类),但你传入的是tournament这个实体实例。
  • 传入实例会导致TypeORM内部无法正确识别实体元数据,进而无法初始化查询构建器,最终抛出InsertQueryBuilderCls is not a constructor的异常。

解决方案

  1. 修正仓库获取逻辑:将getRepository的参数改为实体类(需提前导入对应的实体类)。
  2. 优化SQL参数绑定:存储过程调用中的tournament.tournament_id改为参数绑定形式,避免SQL注入风险。

修正后的代码如下:

// 需提前导入Tournament实体类
import { Tournament } from './entities/tournament.entity';

async savetournamentTransaction(tournament: Tournament, matchId: string) {
    await this.connection.manager.transaction(async (tournamentEntityManager) => {
      // 传入实体类而非实例
      const tournamentRepository = tournamentEntityManager.getRepository(Tournament);
      await tournamentRepository.query(`SET LOCAL search_path to ${matchId}`);
      await tournamentRepository.save(tournament);
      // 使用参数绑定传递tournament_id,避免SQL注入
      await tournamentRepository.query(
        `CALL fillOrganizationScheduleTable($1, $2);`,
        [matchId, tournament.tournament_id],
      );
    });
}

额外注意事项

  • 确保matchId是可信的内部值,因为SET LOCAL search_path无法使用参数绑定,直接拼接存在SQL注入风险,需严格校验输入。
  • 事务内的所有数据库操作必须使用事务提供的tournamentEntityManager或其获取的仓库,确保操作在同一个事务上下文内。

内容的提问来源于stack exchange,提问作者mleko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 12:15:41