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的异常。
解决方案
- 修正仓库获取逻辑:将
getRepository的参数改为实体类(需提前导入对应的实体类)。 - 优化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
相关产品推荐
相关产品推荐

