当 Doctrine 查询已加入时,setMaxResults 无法正常工作

Posted

技术标签:

【中文标题】当 Doctrine 查询已加入时,setMaxResults 无法正常工作【英文标题】:setMaxResults does not works fine when Doctrine query has join 【发布时间】:2018-05-06 11:20:58 【问题描述】:

我想编写一个 DQL 查询来选择帖子并加入另一个实体。

这是我的代码:

   $dql = '
                    SELECT p , h ,t ,m 
                    FROM App:Post p 
                    LEFT JOIN p.mentions m
                    LEFT JOIN p.tags t 
                    LEFT JOIN p.file h 
                    WHERE p.user
                    IN (
                        SELECT f FROM App:User u
                        JOIN u.followers f
                        WHERE u.id = :uid
                       )
                    OR p.user = :uid ';

    $query = $this->getEntityManager()
        ->createQuery($dql)
        ->setMaxResults(5)
        ->setParameters(['uid' => $user->getId()])
        ->getArrayResult();

但问题是setMaxResults不限制posts Entity,而是限制tag Entity on 5。

这是我的两种结果:

1.with setMaxResults (Not work fine)

2.with setMaxResults (Work fine)

我的代码有什么问题?

【问题讨论】:

no setMaxResults 限制标签@Aurelien 【参考方案1】:

这是在没有分页器的情况下使用 setMaxResults()setFirstResult() 时的预期行为

setMaxResults() 实际上是在生成的查询中添加一个 SQL LIMIT,它不仅会限制您所期望的根实体,还会限制查询返回的行.这意味着在加入查询时它不会做你想做的事。

根据First and Max Result Items

如果您的查询包含指定结果限制方法的 fetch-joined 集合,则无法按预期工作。 Set Max Results 限制了数据库结果行的数量,但是在 fetch-joined 集合的情况下,一个根实体可能出现在许多行中,有效地水合少于指定数量的结果。

您可以做的是在查询中使用Paginator

$query = $this->getEntityManager()
    ->createQuery($dql)
    ->setMaxResults(5)
    ->setParameters(['uid' => $user->getId()]);
$paginator = new Paginator($query, $fetchJoinCollection = true);

$c = count($paginator);
foreach ($paginator as $post) 


来自上面的 Paginator 文档链接:

分页 Doctrine 查询并不像您一开始想象的那么简单。如果您有一对多或多对多关联的复杂 fetch-join 场景,使用数据库供应商的“默认”LIMIT 功能不足以获得正确的结果。

另外,请注意:

默认情况下,分页扩展执行以下步骤来计算正确的结果:

使用 DISTINCT 关键字执行 Count 查询。 使用DISTINCT 执行限制子查询以从当前页面中查找实体的所有ID。 执行 WHERE IN 查询以获取当前页面的所有结果。

仅当您实际 fetch join 一个 to-many 集合时才需要此行为。您可以通过将 $fetchJoinCollection 标志设置为 false 来禁用此行为;在这种情况下,只执行 2 个而不是描述的 3 个查询。我们希望将来能自动检测到这一点。

Similar question

【讨论】:

谢谢你的回答,这个答案解决了我的问题,但出现了另一个问题,那就是当我尝试序列化数据服务器时,会被冻结并永远卡住 @mR.Rian 可能你有一个循环引用,例如 Post -> Tags -> Posts 用于序列化,但为此我认为你应该问一个新问题。 这是一个很好的答案。谢谢【参考方案2】:

我建议直接在 DB 上运行此查询(有限制)。您将看到该查询返回 5 行,但只有 3 个唯一帖子。这是因为一个帖子可能有多个标签,所以每个帖子标签的组合都会产生一行。所以 2 个帖子每个有 3 个标签将产生 6 行。设置限制会影响查询返回的行数,它不会神奇地只限制帖子数。将查询结果映射到对象时会删除查询结果中的重复帖子,但此时您只有 3 个唯一帖子。

您可能应该分别查询帖子和标签,而不是使用 limit 与一对多或多对多关系。

【讨论】:

以上是关于当 Doctrine 查询已加入时,setMaxResults 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

加载 Doctrine 固定装置时如何在控制台中禁用查询日志记录?

如何在doctrine zend中没有实体的情况下继续加入查询构建器

Doctrine2 - 加入非相关表

Doctrine查询Builder case语句会抛出意外的语法错误

用于标量查询的 Doctrine 返回数组数组

Doctrine2 - 继承映射,查询子类