Symfony 3.4中基于Doctrine实现真正的动态DQL查询
用Doctrine QueryBuilder实现动态多组OR查询
刚好我之前也遇到过类似的需求,不用把每个like条件写死,咱们可以通过动态循环来生成需要的OR组,完美匹配你想要的效果。
核心思路
你需要把每个字段的多个匹配条件(比如cliente的多个标签)先整合成一个OR组,然后再把这些组组合起来(比如cliente的OR组 AND apoderado的OR组)。
具体实现步骤
初始化QueryBuilder
先创建基础的查询构建器,指定要查询的实体:$entityManager = $this->getDoctrine()->getManager(); $qb = $entityManager->createQueryBuilder(); $qb->select('e') ->from('Your\Entity\Namespace\YourEntity', 'e'); // 替换成你的实体类动态生成单个字段的OR条件组
比如处理cliente的多个标签,我们可以循环标签数组,生成对应的like表达式,再组合成orX:// 假设这是动态传入的cliente标签数组(可以从请求参数、搜索条件等地方获取) $clienteTags = ['tag1', 'tag2', 'tag3']; $clienteConditions = []; foreach ($clienteTags as $index => $tag) { // 生成唯一的参数名,避免冲突 $paramName = 'cliente_tag' . ($index + 1); // 添加like条件到数组 $clienteConditions[] = $qb->expr()->like('e.cliente', ':' . $paramName); // 设置参数值,记得加通配符%,根据需求调整位置(比如只在开头/结尾) $qb->setParameter($paramName, "%{$tag}%"); } // 把所有cliente的like条件组合成一个OR组 $clienteOrGroup = $qb->expr()->orX(...$clienteConditions);用同样的方式处理
apoderado的标签:$apoderadoTags = ['ap_tag1', 'ap_tag2']; // 动态传入的apoderado标签 $apoderadoConditions = []; foreach ($apoderadoTags as $index => $tag) { $paramName = 'apoderado_tag' . ($index + 1); $apoderadoConditions[] = $qb->expr()->like('e.apoderado', ':' . $paramName); $qb->setParameter($paramName, "%{$tag}%"); } $apoderadoOrGroup = $qb->expr()->orX(...$apoderadoConditions);组合多个OR组到查询中
现在把这两个OR组加到where里,根据你的需求选择AND或OR关系(你例子里看起来是AND):$qb->where($clienteOrGroup) ->andWhere($apoderadoOrGroup);优化:封装成复用函数
如果需要多次用到这种动态OR组,可以封装成一个工具函数,减少重复代码:/** * 动态生成某个字段的like OR条件组 * @param \Doctrine\ORM\QueryBuilder $qb * @param string $field 实体字段(比如'e.cliente') * @param array $tags 要匹配的标签数组 * @param string $paramPrefix 参数名前缀,避免冲突 * @return \Doctrine\ORM\Query\Expr\Orx|null */ private function buildDynamicLikeOrGroup(\Doctrine\ORM\QueryBuilder $qb, string $field, array $tags, string $paramPrefix): ?\Doctrine\ORM\Query\Expr\Orx { if (empty($tags)) { return null; // 如果标签为空,返回null,避免生成无效条件 } $conditions = []; foreach ($tags as $index => $tag) { $paramName = "{$paramPrefix}_tag" . ($index + 1); $conditions[] = $qb->expr()->like($field, ":{$paramName}"); $qb->setParameter($paramName, "%{$tag}%"); } return $qb->expr()->orX(...$conditions); }调用方式就很简洁了:
$clienteOrGroup = $this->buildDynamicLikeOrGroup($qb, 'e.cliente', $clienteTags, 'cliente'); $apoderadoOrGroup = $this->buildDynamicLikeOrGroup($qb, 'e.apoderado', $apoderadoTags, 'apoderado'); if ($clienteOrGroup) { $qb->where($clienteOrGroup); } if ($apoderadoOrGroup) { $qb->andWhere($apoderadoOrGroup); }
注意事项
- 参数唯一性:一定要保证每个参数的名字唯一,不然后面的参数会覆盖前面的,导致查询结果错误。
- 空数组处理:如果某个标签数组为空,记得不要生成对应的OR组,否则会导致SQL语法错误。
- 通配符位置:根据你的业务需求调整
%的位置,比如"%{$tag}%"是包含匹配,"{$tag}%"是前缀匹配,"%{$tag}"是后缀匹配。
内容的提问来源于stack exchange,提问作者Juan I. Morales Pestana
相关产品推荐
相关产品推荐

