如何构建动态Doctrine查询?动态生成条件后结果不符
解决Doctrine动态生成OR包裹多组AND查询的问题
你的问题出在两个核心点上:一是没有为每组宽高组合创建独立的andX()表达式,导致查询逻辑完全偏离预期;二是重复使用同一个参数名innerValue,后面的参数值会覆盖前面的,最终查询结果肯定不对。
错误原因拆解
你原来的代码直接把所有width和height的条件都加到了同一个orX()里,生成的逻辑是:
te.width = ? OR te.height = ? OR te.width = ? OR te.height = ?
而你实际需要的是:
(te.width = ? AND te.height = ?) OR (te.width = ? AND te.height = ?)
另外,重复的参数名会让Doctrine最后只保留最后一个参数值,导致前面的条件都绑定了错误的值。
正确的动态实现代码
// 初始化顶级的OR表达式 $orConditions = $qb->expr()->orX(); foreach ($wheres as $groupIndex => $dimensionGroup) { // 为每组宽高创建独立的AND表达式 $andConditions = $qb->expr()->andX(); foreach ($dimensionGroup as $field => $value) { // 生成唯一的参数名,避免覆盖 $paramName = sprintf('dim_%d_%s', $groupIndex, $field); // 向当前AND组添加等于条件 $andConditions->add($qb->expr()->eq("te.$field", ":$paramName")); // 设置对应参数 $qb->setParameter($paramName, $value); } // 把当前AND组添加到顶级OR表达式中 $orConditions->add($andConditions); } // 把最终的OR条件加入查询 $qb->andWhere($orConditions); // 现在输出DQL就能看到和静态写法一致的结果了 dd($qb->getDQL());
代码说明
- 分层创建表达式:先创建顶级的
orX(),再为每组宽高单独创建andX(),这样就能实现(A AND B) OR (C AND D)的嵌套逻辑结构。 - 唯一参数名:用
groupIndex和field拼接成唯一的参数名(比如dim_0_width、dim_0_height),确保每个参数值都能正确绑定,不会被后续值覆盖。 - 使用Doctrine表达式API:用
expr()->eq()替代直接写字符串条件,既能避免SQL注入风险,也更符合Doctrine的最佳实践,适配不同数据库的语法差异。
这样修改后,生成的DQL就会和你静态写法生成的完全一致了。
内容的提问来源于stack exchange,提问作者Znk
相关产品推荐
相关产品推荐

