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

TypeORM泛型基类使用FindOperator报'_type'未知列错误如何解决

TypeORM 0.2.x 泛型基类FindOperator失效问题解决方案

环境信息

  • 运行时:Node v14.19.3
  • 依赖版本:@nestjs/typeorm@~8.0.3、typeorm@~0.2.45

问题现象

封装通用CRUD泛型基类CrudService<T>时,在基类内部直接使用Between()、Like()等FindOperator编写查询,会生成错误SQL,抛出Unknown column '_type' in 'where clause'错误;完全相同的查询逻辑移动到继承该基类的子类服务中即可正常运行,两种场景使用的是同一个Repository实例。

异常基类代码

export class CrudService<T> {
    protected repository: Repository<T>;

    constructor(repository: Repository<T>) {
        this.repository = repository;
    }
    // 其余通用CRUD方法已省略
    async find() {
        return this.repository.find({
            where: {
                created: Between("2022-06-21T14:18:00.000Z", "2022-06-21T14:19:00.000Z")
            }
        });
    }
}

错误输出

基类调用find方法时生成的错误SQL将FindOperator作为普通值做等值比较:

SELECT ... FROM `carts` `CartEntity` WHERE `CartEntity`.`created` = ?

绑定参数为FindOperator的内部属性对象:

{
    "_type":"between",
    "_value":[
        "2022-06-21T14:18:00.000Z",
        "2022-06-21T14:19:00.000Z"
    ],
    "_useParameter":true,
    "_multipleParameters":true
}

正常子类实现

相同逻辑写在子类中可正常生成BETWEEN查询语句:

@Injectable()
export class CartsService extends CrudService<CartEntity> {
    constructor(
        @InjectRepository(CartsRepository) repository: CartsRepository
    ) {
        super(repository);
    }
    // 其余方法已省略
    async find() {
        return this.repository.find({
            where: {
                created: Between("2022-06-21T14:18:00.000Z", "2022-06-21T14:19:00.000Z")
            }
        });
    }
}

根因

这是TypeORM 0.2.x版本的已知设计缺陷:
框架判断where条件中的值是否为FindOperator类型,依赖instanceof FindOperator校验。JS中instanceof判断的核心是校验对象原型链上是否存在对应构造函数的prototype,如果项目中存在多份TypeORM模块副本,会出现两边构造函数引用不一致的问题:

  • 基类文件中导入的Between等操作符来自A份TypeORM包,生成的FindOperator实例原型指向A包的FindOperator.prototype
  • Nest注入的Repository实例由B份TypeORM包创建,校验时使用的是B包的FindOperator构造函数
    两边引用不匹配导致instanceof校验返回false,框架会将FindOperator实例当做普通对象处理,直接序列化做等值比较。
    子类中代码正常运行的原因是:子类文件与Nest TypeORM模块注册逻辑在同一个依赖解析上下文,导入的操作符和Repository实例来自同一份TypeORM包,instanceof校验可以通过。

解决方案

可根据项目实际情况选择以下任意一种方案修复:

  • 方案1:消除TypeORM多副本
    执行包管理工具的依赖查询命令检查项目中存在的TypeORM版本:
    • npm用户执行npm ls typeorm
    • yarn用户执行yarn why typeorm
    • pnpm用户执行pnpm ls typeorm
      将所有依赖引用的TypeORM版本对齐到0.2.45,删除lock文件和node_modules目录后重新安装依赖,保证整个项目中只存在一份TypeORM包,所有位置导入的FindOperator引用保持一致。
  • 方案2:使用QueryBuilder替代find选项写法
    QueryBuilder不会触发FindOperator的instanceof校验,不需要修改依赖即可直接修复问题,适合不想调整依赖结构的场景:
    async find() {
      return this.repository.createQueryBuilder('entity')
        .where('entity.created BETWEEN :start AND :end', {
          start: "2022-06-21T14:18:00.000Z",
          end: "2022-06-21T14:19:00.000Z"
        })
        .getMany();
    }
    
  • 方案3:配置TS路径映射强制单例
    在项目tsconfig.json中添加路径映射规则,强制所有文件导入TypeORM时都解析到项目根目录下的同一个包入口:
    {
      "compilerOptions": {
        "baseUrl": "./",
        "paths": {
          "typeorm": ["node_modules/typeorm"]
        }
      }
    }
    
    Monorepo项目注意调整路径指向工作区根目录的TypeORM包,避免子包独立安装依赖产生副本。
  • 方案4:升级依赖版本
    TypeORM 0.3.x版本重构了FindOperator的实现逻辑,不再依赖instanceof做类型校验,从根源上消除了该问题。对应需要将@nestjs/typeorm升级到9.x及以上版本适配TypeORM 0.3.x。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:48:21