Doctrine多对多关联下排除指定标签的Story查询实现问题
实现方案
方案1:LEFT JOIN + IS NULL实现(无需子查询,推荐)
// 仅当排除标签非空时添加过滤,避免空数组导致的查询错误 if (!empty($excludeTags)) { $qb->leftJoin('s.tags', 'et', \Doctrine\ORM\Query\Expr\Join::WITH, 'et IN (:excludeTags)') ->andWhere('et IS NULL') ->setParameter('excludeTags', $excludeTags); }
逻辑说明:
LEFT JOIN时仅匹配你指定的排除标签,如果某个Story包含任意一个排除标签,关联字段et就会有对应值,我们直接过滤掉et不为空的记录,就能得到完全不包含任何排除标签的Story。
方案2:子查询实现(和你原生SQL逻辑完全对齐)
if (!empty($excludeTags)) { // 子查询查出所有关联了排除标签的Story ID $subQb = $this->createQueryBuilder('sub_s') ->select('sub_s.id') ->join('sub_s.tags', 'et', \Doctrine\ORM\Query\Expr\Join::WITH, 'et IN (:excludeTags)'); $qb->andWhere($qb->expr()->notIn('s.id', $subQb->getDQL())) ->setParameter('excludeTags', $excludeTags); }
ORM会自动处理多对多关联表的映射逻辑,不需要你手动写关联表的查询条件。
之前写法的错误原因
- 首次用
ON关键字报错:Doctrine中关联实体自身定义的关联属性时,join条件只能用WITH关键字,ON仅用于关联未在实体中映射的表场景 - 直接写
s.tags NOT IN报错:s.tags是集合类型的关联字段,不能直接用IN/NOT IN做判断,必须join后针对单条关联记录做判断 - 改
WITH后过滤不生效:你之前写的et NOT IN (:excludeTags)只是关联非排除的标签,只要Story有任意一个非排除标签就会被匹配,完全没有过滤带排除标签的记录,逻辑本身错误。
内容的提问来源于stack exchange,提问作者Christian Riesen
相关产品推荐
相关产品推荐

