我可以通过检查 id 是否为 null 来优雅地加入 Doctrine 吗?

Can I left join gracefully with Doctrine by checking id against null?

我实现了如下功能,和我实际想要的很接近:

public function loadUserGroupsOfNewsletter($ids, $newsletterID)
{
    $qb = $this->getEntityManager()->createQueryBuilder();
    return $qb->select('ug, gon')
              ->from('MyNameSpace:UserGroup', 'ug')
              ->leftJoin('ug.groupsOfNewsletter', 'gon')
              ->leftJoin('gon.newsletterItem', 'n')
              ->where($qb->expr()->in('ug.id', $ids))
              ->where('n.id = :id')
              ->setParameter('id', $newsletterID)
              ->getQuery()->getResult();
}

我想为每个用户组至少获取一条记录。如果没有与时事通讯的 id 匹配的时事通讯,那么对于给定的结果项,我希望 gonnull,但如果至少有与 id 匹配的时事通讯,那么我希望在结果项中有正确的用户组和 gon 记录。

所以,

案例 1. 给定的用户组没有匹配的新闻通讯:

结果项应包含正确的 ugnull 作为 gon

案例 2. 给定的用户组至少有一个匹配的时事通讯:

简报项目的数量与存在的匹配项数量一样多,该用户组的所有结果项目都将包含有效的 uggon

我已尝试检查 n.id 是否为 null,结果符合我的预期,因此我假设以下查询实现了我的预期,因为我的实验产生了良好的结果。我的假设是否正确?

public function loadUserGroupsOfNewsletter($ids, $newsletterID)
{
    $qb = $this->getEntityManager()->createQueryBuilder();
    return $qb->select('ug, gon')
              ->from('MyNameSpace:UserGroup', 'ug')
              ->leftJoin('ug.groupsOfNewsletter', 'gon')
              ->leftJoin('gon.newsletterItem', 'n')
              ->where($qb->expr()->in('ug.id', $ids))
              ->where('(n.id is null) or (n.id = :id)')
              ->setParameter('id', $newsletterID)
              ->getQuery()->getResult();
}

从外观上看,应该 没问题,但我不确定您希望通过返回订阅此特定时事通讯的用户和那些已订阅的用户来实现什么目的没有订阅任何?

您可以尝试将这些谓词移动到 IN 语句(WITH in Doctrine):

->leftJoin('ug.groupsOfNewsletter', 'gon')
->leftJoin('gon.newsletterItem', 'n', 'WITH', 'n.id = :id')

这有意义吗?可能我误解了你的意思。

另一件引起我注意的事情是 where 的双重使用。根据 Doctrine 的来源,where 看起来像这样:

public function where($predicates)
{
    if (! (func_num_args() === 1 && $predicates instanceof Expr\Composite)) 
    {
        $predicates = new Expr\Andx(func_get_args());
    }

    return $this->add('where', $predicates);
}

add 具有以下签名:

public function add($dqlPartName, $dqlPart, $append = false)

换句话说,您后续的 where 不会被追加,而是会覆盖前一个。

你可能应该使用 andWhere 来做你想做的事。

希望对您有所帮助...