2

考虑以下 DQL:

SELECT
  a,
  (SELECT COUNT(c.id) FROM Comment c WHERE c.article_id = a.id) num_comments
FROM Article a

我希望结果包含所有文章列以及同一级别的 num_comments,但是文章列被包装在索引 0 处的数组中:

array(
  0 => array(
    0 => array(
      "id" => 1,
      "title" => "Title",
    ),
    "num_comments" => 15
  ),
  1 => array(
    0 => array(
      "id" => 2,
      "title" => "Title",
    ),
    "num_comments" => 20
  )
);

如何将所有文章列和任何额外字段保持在同一级别?

4

2 回答 2

3

我将把我的答案分成简短的解释(和替代答案)。

简短说明:

SELECT a.field1
     , ...
     , a.fieldN
     , (SELECT COUNT(c.id) FROM Comment c WHERE c.article_id = a.id) num_comments 
  FROM Article a

然后作为 ARRAY 水合物,它会返回您所期望的。

长解释:

每当您引用实体本身时(在您的情况下为“SELECT a”),这意味着您正在请求返回与任何其他元素隔离的整个实体。默认情况下,Doctrine 始终将此实体分配给索引 0,并根据您选择的 FROM 实体的数量继续。要更改此行为,您所要做的就是为实体设置别名,就像您对子查询所做的那样:

SELECT a AS article
     , (SELECT COUNT(c.id) FROM Comment c WHERE c.article_id = a.id) AS num_comments 
  FROM Article a

这将返回到类似的内容:

array(
  0 => array(
    "article" => array(
      "id" => 1,
      "title" => "Title",
    ),
    "num_comments" => 15
  ),
  1 => array(
    "article" => array(
      "id" => 2,
      "title" => "Title",
    ),
    "num_comments" => 20
  )
);

如果您不希望返回整个实体,则可以使用 PARTIAL 支持并仅返回您感兴趣的字段。让我们支持您只需要 id(强制性,因为它是实体标识符)和标题:

SELECT PARTIAL a.{id, title} AS article
     , (SELECT COUNT(c.id) FROM Comment c WHERE c.article_id = a.id) AS num_comments 
  FROM Article a

另一种方法是将结果封装到 DTO 中。当您决定将值水合为对象时,这将提供更多的 OO 控制。DQL 看起来像这样:

SELECT NEW ArticleDTO(a, COUNT(c.id)) 
  FROM Article a
  LEFT JOIN a.comments c
 GROUP BY a.id

您不能将整个子查询作为参数放置的原因是由于 DQL 的限制。从来没有人请求过完整的子查询,所以现在我们遵循 JPA 建议的 ScalarExpression。

干杯,

吉尔赫姆·布兰科

于 2013-08-08T04:16:10.560 回答
0

@hari 提到的非常接近答案。

您只需要执行 LEFT JOIN 即可获得所有文章,即使它们没有评论。

 SELECT a, COUNT(c.id) AS num_comments FROM Article a LEFT JOIN a.comments c GROUP BY a.id 

并将 COUNT 放在与文章相同的数组中,我会说 SELECT by the fields 单独。

SELECT a.id, a.text, a.date, COUNT(c.id) AS num_comments FROM Article a LEFT JOIN a.comments c GROUP BY a.id 
于 2013-08-08T03:30:45.763 回答