为什么Doctrine QueryBuilder未手动添加WHERE子句却自动生成?
问题原因
这个自动生成的WHERE a3_.id IN (...)子句不是Doctrine ORM本身生成的,而是你使用的Symfony分页组件(PaginatorInterface)自动注入的。
具体逻辑
Symfony分页组件针对包含GROUP BY、多表关联(尤其是一对多关联)的查询,默认会开启优化逻辑:
- 先执行一次计数查询,提取满足条件的主表(这里是
asset表)的主键ID列表 - 把ID列表作为
WHERE IN条件注入到最终执行的查询中,避免重复计算分组、减少关联查询的开销
你调用resetDQLPart('where')无效的原因是:这个条件是分页组件在你调用paginate()方法后,处理QueryBuilder时追加的,你重置的是自己代码里写的WHERE条件,不影响分页组件后续的注入逻辑。
解决方案
你可以根据需求任选一种方案:
方案1:禁用分页组件的自动查询包裹逻辑
在调用paginate()方法时增加参数,关闭输出walker和查询包裹特性:
$pagination = $paginator->paginate( $queryBuilder, $request->query->getInt('page', 1), 50000, [ 'use_output_walkers' => false, 'wrap_queries' => false ] );
方案2:直接获取结果不使用分页
你当前设置的单页条数是50000,已经远大于常规业务的单页数据量,如果不需要分页功能,可以直接执行查询获取结果,绕过分页组件的逻辑:
$results = $queryBuilder->getQuery()->getResult();
方案3:给查询设置Hint禁用分页优化
也可以直接给Doctrine查询对象设置Hint,关闭分页相关的优化逻辑:
$query = $queryBuilder->getQuery(); $query->setHint(\Doctrine\ORM\Tools\Pagination\Paginator::HINT_ENABLE_DISTINCT, false); $pagination = $paginator->paginate($query, $request->query->getInt('page', 1), 50000);
补充说明
如果上述方案无效,可以检查你的Asset实体是否配置了全局过滤规则(比如软删除过滤器、租户过滤规则等),这类过滤器也会自动追加WHERE条件,需要手动关闭对应过滤器。
内容的提问来源于stack exchange,提问作者MartynWoollard
相关产品推荐
相关产品推荐

