在Doctrine中用自定义DQL表达式构建OR条件时遇错如何解决?
解决Doctrine Criteria OR表达式结合自定义JSON_CONTAINS函数的报错问题
问题原因
你当前的代码直接把SQL字符串传给Criteria::expr()->orX(),但这个方法要求传入的是Doctrine的表达式对象(实现ExpressionInterface),而非原始SQL字符串,因此会触发No expression given to CompositeExpression错误。
修正方案
下面提供两种安全且有效的实现方式,同时避免SQL注入风险:
方案1:基于Criteria构建表达式并绑定参数
private function filterAgeGroups(array $ageGroups) { $expr = Criteria::expr(); $criterias = []; foreach ($ageGroups as $index => $ageGroup) { // 构建JSON_CONTAINS的比较表达式 $jsonCondition = $expr->comparison( "JSON_CONTAINS(g.ageGroupIds, :ageGroup$index)", '=', 1 ); $criterias[] = $jsonCondition; } return $expr->orX(...$criterias); }
使用时需要在QueryBuilder中绑定对应参数:
$ageGroups = [/* 你的年龄组数据 */]; $ageCriteria = $this->filterAgeGroups($ageGroups); $qb->addCriteria($ageCriteria); // 循环绑定每个参数 foreach ($ageGroups as $index => $ageGroup) { $qb->setParameter("ageGroup$index", (string)$ageGroup); }
方案2:直接通过QueryBuilder的Expr构建OR条件
如果你的场景不需要单独返回Criteria,也可以直接在QueryBuilder中操作:
private function addAgeGroupFilter($qb, array $ageGroups) { $expr = $qb->expr(); $conditions = []; foreach ($ageGroups as $index => $ageGroup) { // 用expr()->eq包裹自定义函数调用 $conditions[] = $expr->eq( "JSON_CONTAINS(g.ageGroupIds, :ageGroup$index)", 1 ); } if (!empty($conditions)) { $qb->andWhere($expr->orX(...$conditions)); // 绑定参数 foreach ($ageGroups as $index => $ageGroup) { $qb->setParameter("ageGroup$index", (string)$ageGroup); } } return $qb; }
调用方式:
$qb = $entityManager->createQueryBuilder(); // 其他查询构建逻辑... $this->addAgeGroupFilter($qb, [/* 年龄组数组 */]);
关键注意事项
- 绝对不要直接把
$ageGroup拼接到SQL字符串中,必须通过参数绑定(:ageGroup$index)避免SQL注入风险,这和你第二段正常工作的代码逻辑保持一致。 orX()方法仅接受Doctrine表达式对象,不能直接传原始SQL字符串,这是你之前报错的核心原因。
内容的提问来源于stack exchange,提问作者David Schilling
相关产品推荐
相关产品推荐

