WHERE ... 在 Doctrine queryBuilder 或等效的子查询中进行查询

WHERE ... IN query with sub-query in Doctrine queryBuilder or equivalent

在我的 Symfony 4 项目中,我有一个 User 实体和一个 UserRepository。 我正在尝试在 QueryBuilder(Doctrine 2) 甚至 DQL.

中实现与此 SQL 查询等效的查询
SELECT * FROM user WHERE account_manager_id IN (SELECT id FROM user WHERE account_manager_id = :managerAdminId AND roles LIKE '%ROLE_MANAGER%')

或者使用不同的语法。

我尝试了不同的方法,但无法弄清楚如何使用子查询编写 WHERE ... IN。

这就是我能想到的全部,我不喜欢它,因为它会触发多个查询,以获取我可以用一个查询完成的事情:

    //App\Repository\UserRepository

    public function getPublishersOfManagers($managerAdminId)
    {
        //SELECT * FROM user WHERE account_manager_id IN (SELECT id FROM user WHERE account_manager_id = :managerAdminId AND roles LIKE '%ROLE_MANAGER%')

        $managerIds = $this->createQueryBuilder('u')
                    ->select('u.id')
                    ->where('u.roles LIKE :role')
                    ->setParameter('role' , '%ROLE_MANAGER%')
                    ->andWhere('u.accountManager = :managerAdminId')
                    ->setParameter('managerAdminId' , $managerAdminId)
                    ->getQuery()->getArrayResult();

        $publishers = [];

        foreach ($managerIds as $id) {

            $publishers[] = $this->createQueryBuilder('u')
                    ->select('u')
                    ->where('u.roles LIKE :role')
                    ->setParameter('role' , '%ROLE_PUBLISHER%')
                    ->andWhere('u.accountManager = :managerAdminId')
                    ->setParameter('managerAdminId' , $id)
                    ->getQuery()->getResult();
        }

        return $publishers;
    }

根据DQL query examples section within Doctrine's DQL documentation you need to either use EXISTS keyword within DQL query or use exists() method of Expr class.

你的查询可以变成没有子查询的东西,但是有一个连接,它应该是等价的(并且应该有相同的runtime/complexity)

SELECT u 
FROM user u 
LEFT JOIN user am ON (am.id=u.accountManager) 
WHERE am.roles LIKE '%ROLE_MANAGER%' 
  AND am.accountManager=:managerAdminId
  AND u.roles LIKE '%ROLE_PUBLISHER%'

可以相应地翻译成查询生成器(我必须假设,你没有定义你的关联......我觉得这很令人不安,但你可能有你的理由):

return $this->createQueryBuilder('u')
  ->leftJoin('App\Entity\User', 'am', 'WITH', 'am.id=u.accountManager')
  ->andWhere('am.roles LIKE :role')
  ->setParameter('role', '%ROLE_MANAGER%')
  ->andWhere('am.accountManager = :managerAdminId')
  ->setParameter('managerAdminId', $managerAdminId)
  ->andWhere('u.roles LIKE :role2')
  ->setParameter('role2', '%ROLE_PUBLISHER%')
  ->getQuery()->getResult();

实际上还有 using sub-queries 的选项,但是恕我直言,使用子查询总是不方便 - 而且很难看。

(您可能会考虑编写简单的 DQL 查询,您可能会感觉更自在......?)