Doctrine2+Symfony多对多场景查询完全匹配参与者的讨论避免重复
问题原因
你当前的写法逻辑存在错误:MEMBER OF 语法用于判断单个元素是否属于集合,直接传入ID数组的匹配逻辑是「讨论的参与者中存在至少一个ID属于传入的数组」,所以只要参与者有重叠就会被命中,完全不符合你要的完全匹配需求。
解决思路
要实现参与者完全一致的匹配,需要同时满足两个判断条件:
- 讨论包含所有你传入的参与者
- 讨论的参与者总数和你传入的参与者数量完全相等
两个条件同时满足即可保证讨论没有多余的参与者,和传入列表完全匹配。
修改后代码
public function findDiscussionsWithThisParticipants(array $participants) { $participantIds = array_map(function($o) { return $o->getId();}, $participants); $targetParticipantCount = count($participantIds); $queryBuilder = $this->createQueryBuilder('d') ->join('d.participants', 'p') ->where('p.id IN (:participantIds)') ->setParameter('participantIds', $participantIds) ->groupBy('d.id') // 条件1:匹配到的参与者数量等于目标数量,说明所有目标参与者都在该讨论中 ->having('COUNT(DISTINCT p.id) = :targetCount') // 条件2:该讨论的总参与者数量等于目标数量,说明没有多余参与者 ->andHaving('SIZE(d.participants) = :targetCount') ->setParameter('targetCount', $targetParticipantCount); return $queryBuilder ->getQuery() ->getResult(); }
逻辑验证
对应你给出的示例场景,传入[User A, User D]时:
- discussion 1 总参与者数是3,直接被第二个HAVING条件过滤
- discussion 2 总参与者数是2,且匹配到的参与者为A和D,COUNT值为2,符合条件被保留
- discussion 3 没有匹配到A或D,COUNT值为0,被第一个HAVING条件过滤
最终仅返回discussion 2,完全符合预期。
内容的提问来源于stack exchange,提问作者Aymeric
相关产品推荐
相关产品推荐

