TypeORM多参数过滤不同类型值报Operand should contain 1 column(s)错误
问题根因
直接将_.pickBy生成的普通过滤对象传入where()方法时,TypeORM默认会将对象解析为字段=值的等值匹配逻辑:
- 字段值为单值(比如数字类型的
orgId、单元素数组)时,TypeORM可以正常解析为等值查询 - 字段值为多元素数组时,TypeORM不会自动转换为
IN查询,反而会生成类似WHERE status = ('approved', 'pending')的非法SQL,等于号右侧出现多值集合就会抛出Operand should contain 1 column(s)错误。
修复方案
不要直接传递原生对象作为where条件,手动区分单值等值匹配、数组值IN匹配场景,使用TypeORM原生条件构造+参数绑定实现,同时规避SQL注入风险。
直接在查询构造阶段遍历合法字段拼接条件即可,无需保留原有返回原生对象的getFilterConditions逻辑,修复后的代码如下:
protected getAll(filter: GetAllDataFilter): SelectQueryBuilder<EntityName> { const qb = Repository<EntityName> .createQueryBuilder('entityName') .select([ 'entityName.id', 'entityName.status', 'entityName.orgId', ]) .groupBy('entityName.id'); Object.entries(filter).forEach(([key, value]) => { // 跳过非实体字段、未传值的参数 if (!this.entityProperties.has(key) || value === undefined) return; if (Array.isArray(value)) { // 数组类型参数走IN查询 qb.andWhere(`entityName.${key} IN (:...${key})`, { [key]: value }); } else { // 单值参数走等值匹配 qb.andWhere(`entityName.${key} = :${key}`, { [key]: value }); } }); return qb; }
如果需要拆分条件构造逻辑,也可以把遍历拼接条件的部分单独抽到getFilterConditions方法中,接收qb实例做条件追加即可,不要返回原生对象直接传给where()。
效果说明
传入过滤条件{ orgId: 12345, status: ['approved', 'pending'] }时,最终生成的SQL片段为:
WHERE entityName.orgId = 12345 AND entityName.status IN ('approved', 'pending')
完全满足多值枚举匹配、单值精确匹配、可选参数任意组合的过滤需求,所有参数通过TypeORM内置机制绑定,不存在SQL注入风险。
内容的提问来源于stack exchange,提问作者kayvera
相关产品推荐
相关产品推荐

