TypeORM QueryBuilder与EntityManager相同条件count结果不一致问题
问题描述
两段预期逻辑完全一致的TypeORM查询返回了不同结果,相关代码如下:
console.log( await em .createQueryBuilder(OrderItemEntity, 'orderItem') .where({ id: orderItem.id }) .andWhere({ ownedByInvoice: IsNull() }) .getCount(), ); // 返回0,符合预期 console.log( await em.count(OrderItemEntity, { where: { id: orderItem.id, ownedByInvoice: IsNull() }, }), ); // 返回1,错误统计到了ownedByInvoice字段非空的记录
实际执行表现:
- QueryBuilder写法:指定id匹配条件后追加
ownedByInvoice为空的筛选,调用getCount()返回结果0,符合预期。 - EntityManager.count写法:传入完全相同的筛选条件,返回结果1,错误统计到
ownedByInvoice字段非空的记录。
原因说明
这个问题是TypeORM不同查询入口的条件解析规则不统一导致的,属于框架已知逻辑缺陷,不是使用方式错误:ownedByInvoice是实体的关联字段(非主表普通字段),QueryBuilder处理顶层传入的IsNull()条件时,会自动生成关联表的LEFT JOIN逻辑,正确判断关联是否为空;但count/find这类仓储快捷方法在0.3.17之前的版本中,直接给关联属性传IsNull()时不会自动生成关联表JOIN语句,导致该判空条件完全不生效,最终返回错误统计结果。
修复方案
- 调整count方法的where条件写法,显式指定关联主键判空,触发TypeORM自动生成关联JOIN:
await em.count(OrderItemEntity, { where: { id: orderItem.id, ownedByInvoice: { id: IsNull() } }, })
- 升级TypeORM到0.3.17及以上的稳定版本,新版本已经修复了仓储方法解析关联字段
IsNull()条件的逻辑问题,原写法可直接返回正确结果。 - 涉及关联条件的查询统一使用QueryBuilder编写,避免快捷方法隐式生成SQL带来的逻辑不一致问题。
内容的提问来源于stack exchange,提问作者C TC
相关产品推荐
相关产品推荐

