Symfony多对多关联下QueryBuilder AND查询属性结果为空问题
问题原因
你遇到的是多对多关联查询的典型逻辑错误:
- 单次JOIN关联
attributes表时,每一条查询结果行对应的是单个Product关联单个Attribute的组合 - 此时
a.slug字段在单行中只能存在一个值,永远不可能同时满足a.slug = 'red' AND a.slug = 'blue'的条件,所以查询结果为空 - OR条件只要匹配任意一个属性就可以命中,所以查询正常
解决方案
方案1:固定属性数量场景,多次关联属性表
每个需要匹配的属性单独做一次JOIN,分别设置筛选条件:
public function findByAttributes() { $qb = $this->createQueryBuilder('p') // 第一次关联匹配red属性 ->join('p.attributes', 'a1') ->andWhere('a1.slug = :slug1') ->setParameter('slug1', 'red') // 第二次关联匹配blue属性 ->join('p.attributes', 'a2') ->andWhere('a2.slug = :slug2') ->setParameter('slug2', 'blue') ; return $qb->getQuery()->getResult(); }
方案2:动态多属性匹配场景,用分组统计数量
如果需要灵活传入任意数量的属性筛选,用GROUP BY + 匹配数量校验的方案扩展性更强,同时可以用上你方法定义的$attributes参数:
public function findByAttributes(array $attributeSlugs) { $qb = $this->createQueryBuilder('p') ->join('p.attributes', 'a') // 匹配所有传入的属性slug ->andWhere('a.slug IN (:slugs)') ->setParameter('slugs', $attributeSlugs) // 按产品ID分组 ->groupBy('p.id') // 匹配到的属性数量等于传入的属性总数,说明该产品关联了所有要求的属性 ->having('COUNT(DISTINCT a.slug) = :slugCount') ->setParameter('slugCount', count($attributeSlugs)) ; return $qb->getQuery()->getResult(); } // 调用示例:筛选同时有red、blue属性的产品 $products = $productRepository->findByAttributes(['red', 'blue']);
这里加
DISTINCT是为了避免产品重复关联同一个属性的异常场景导致统计错误,如果你的业务逻辑里不会出现该情况,可以去掉DISTINCT。
内容的提问来源于stack exchange,提问作者NGrdanjski
相关产品推荐
相关产品推荐

