DQL 中带有子查询的 Doctrine JOIN

Doctrine JOIN with subquery in DQL

我有这个 SQL:

SELECT
s.id,
e.exception,
s.name,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name as partner,
p.id as partnerId,
group_concat(c.name) names,
group_concat(c.email) emails,
group_concat(c.tel) tels
FROM
service s
JOIN web w ON s.web_id = w.id
JOIN rus r ON w.rus_id = r.id
JOIN partner p ON r.partner_id = p.id
LEFT JOIN exception e ON e.service_id = s.id
JOIN contact c ON c.partner_id = c.id
where c.main = 1 or c.important = 1
group by s.id

当我尝试将其转换为 DQL 时

$result = $this->_em
    ->createQuery(
        'SELECT s.name, w.webId, r.email, p.name as PartnerName
         FROM App\Model\Database\Entity\Service s
         JOIN App\Model\Database\Entity\Web w WITH s.web = w.id
         JOIN App\Model\Database\Entity\Rus r WITH w.rus = r.id
         JOIN App\Model\Database\Entity\Partner p WITH r.partner = p.id
         LEFT JOIN App\Model\Database\Entity\Exception e WITH e.service = s.id
         LEFT JOIN (SELECT
         p.id,
         group_concat(c.name) names,
         group_concat(c.tel) tels,
         group_concat(c.email) emails
         FROM
         App\Model\Database\Entity\Partner p
         LEFT JOIN App\Model\Database\Entity\Contact c WITH c.partner = p.id
         where c.main = 1 or c.important = 1
         group by p.id) test
         WHERE test.id = p.id'
    )->getResult();

return new ArrayCollection($result);

我得到:

[Semantical Error] line 0, col 452 near 'JOIN (SELECT\r\n ': Error: Subquery is not supported here

使用 QueryBuilder 是一样的..

在 DQL 中或使用 QueryBuilder 中,是否有任何 hack 可以将左连接与子查询一起使用?

谢谢

#3542

中的回答

DQL is about querying objects. Supporting subselects in the FROM clause means that the DQL parser is not able to build the result set mapping anymore (as the fields returned by the subquery may not match the object anymore).

您最好的选择是使用 sql 而不是

$conn = $this->getEntityManager()->getConnection();
$sql = 'Your query';
$stmt = $conn->prepare($sql);
$stmt->execute(); //Bind what parameters you need

当您可以使用连接和聚合处理时,我认为您不需要子查询。就像在主查询中一样,加入您的 contact 实体并为您想要的结果集执行聚合。我已经更新了 group by 子句并添加了 select 子句中的所有非聚合列,这样即使启用了 mysql 的严格模式,该查询也将有效,请参阅 MySQL Handling of GROUP BY 和它也将根据分组标准消除重复行

在SQL会像

SELECT
    s.id,
    s.name,
    e.exception,
    w.url,
    w.web_id,
    w.active,
    w.suspended,
    r.email,
    p.name as partnerName,
    p.id as partnerId,
    group_concat(c.name) names,
    group_concat(c.email) emails,
    group_concat(c.tel) tels
FROM service s
    left join exception e ON e.service_id = s.id
    join web w ON s.web_id = w.id
    join rus r ON w.rus_id = r.id
    join partner p ON r.partner_id = p.id
    join contact c ON c.partner_id = c.id 
WHERE c.main = 1 or c.important = 1
GROUP BY s.id,
        s.name,
        e.exception,
        w.url,
        w.web_id,
        w.active,
        w.suspended,
        r.email,
        p.name,
        p.id

我相信你需要添加一个扩展来支持 Mysql 的 GROUP_CONCAT 学说默认功能,这不包含在学说 orm 中。

要添加对 GROUP_CONCAT in doctrine 的支持,您可以按照链接答案中提到的步骤进行操作。注册后,您可以将原始 SQL 转换为 DQL as

SELECT  s.id,
        s.name,
        e.exception,
        w.url,
        w.web_id,
        w.active,
        w.suspended,
        r.email,
        p.id as partnerId,
        p.name as partnerName,
        GROUP_CONCAT(c.name) contactNames,
        GROUP_CONCAT(c.email) contactEmails,
        GROUP_CONCAT(c.tel) contactTels
FROM App\Model\Database\Entity\Service s
    LEFT JOIN App\Model\Database\Entity\Exception e WITH e.service = s.id
    JOIN App\Model\Database\Entity\Web w WITH s.web = w.id
    JOIN App\Model\Database\Entity\Rus r WITH w.rus = r.id
    JOIN App\Model\Database\Entity\Partner p WITH r.partner = p.id
    JOIN App\Model\Database\Entity\Contact c WITH c.partner = p.id
WHERE c.main = 1 or c.important = 1
GROUP BY s.id,
        s.name,
        e.exception,
        w.url,
        w.web_id,
        w.active,
        w.suspended,
        r.email,
        p.name,
        p.id
    

或者另一种方法是使用 ResultSetMapping class 的学说,您可以在其中执行原始 SQL 并将结果映射到各个实体

$rsm = new ResultSetMapping;
$rsm->addEntityResult('App\Model\Database\Entity\Service', 's');
$rsm->addFieldResult('s', 'id', 'id');
$rsm->addFieldResult('s', 'name', 'name');
$rsm->addJoinedEntityResult('App\Model\Database\Entity\Exception' , 'e', 's', 'exception');
$rsm->addFieldResult('e', 'exception', 'exception');
//.... other relations
$rsm->addJoinedEntityResult('App\Model\Database\Entity\Partner' , 'p', 'r', 'partner');
$rsm->addFieldResult('p', 'partnerName', 'name');
$rsm->addScalarResult('contactNames', 'contactNames');
// ... and so on

$sql = 'SELECT s.id, e.exception ... FROM service s JOIN ... WHERE ... GROUP BY s.id, e.exception ...';
$query = $this->_em->createNativeQuery($sql, $rsm);
$data = $query->getResult();