当 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中没有实体的情况下继续加入查询构建器