如何使用fetch-joined集合来限制Doctrine查询?

33

我有一个Doctrine查询,返回博客文章及其评论:

SELECT b, c FROM BlogPost b LEFT JOIN b.comments c

我希望将结果限制为10篇博客文章。根据DQL文档,setMaxResults()在查询包含关联集合(在此情况下是评论)时无法正确使用:

如果你的查询包含一个fetch-joined集合,那么指定结果限制方法将不能按照预期工作。设置Max Results限制了数据库结果行数,然而在fetch-joined集合的情况下,一个根实体可能会出现在多行中,从而实际上提取的结果数量小于指定的结果数。

如何正确地限制包含fetch-joined集合的Doctrine查询(在这种情况下,将结果限制为10篇博客文章)?

5个回答

35

Paginate已与doctrine 2.2合并,新的symfony2发布版本2.0.10与之兼容。

现在可以这样使用

//use Doctrine paginator
use Doctrine\ORM\Tools\Pagination\Paginator;

编写查询语句,然后调用结果就像这样。

$query->setMaxResults($limit);
$query->setFirstResult($offset);
$results = new Paginator($query, $fetchJoin = true);
希望这可以帮助你。
注意:如果你使用的是SF2 2.0.10版本,你应该更新deps和deps.lock文件,并在Doctrine bundles中指定2.2版本。

1
这里需要注意的是,foreach ($results as $post) { echo $post "\n"; } 中的 $post 表示数据中的每一行。 - Jason Liu

3

谢谢。你介意分享一下如何在不使用DoctrineExtensions的情况下完成这个任务吗?现在,我不想包含任何绝对不必要的额外库。我认为这也会使未来的许多读者受益。 - Stephen Watkins
你应该查看扩展的代码。它有:首先:一个 SELECT DISTINCT mainentity.id WHERE 语句来获取所有的id。其次:一个带有 WHERE id IN (..) 的 Select 语句,其中包含之前获取的id。第三:一个 SELECT DISTINCT 语句用于获取总结果数。 - beberlei
谢谢,我现在明白了发生了什么。不过我最终还是使用了扩展。看起来有很多有用的扩展而且没有太多开销。 - Stephen Watkins

0
如果你使用KnbPaginator,你只需要

config/packages/knp_paginator.yaml

knp_paginator:
  page_range: 10                     # number of links shown in the pagination menu (e.g: you have 10 pages, a page_range of 3, on the 5th page you'll see links to page 4, 5, 6)
  default_options:
    page_name: page                 # page query parameter name
    sort_field_name: sort           # sort field query parameter name
    sort_direction_name: order      # sort direction query parameter name
    distinct: false  # <<< ADD THIS LINE <<<

或者你可以这样做

$paginator = $this->container->get(PaginatorInterface::class);
$paginator->paginate($query, $page, $limit, ['distinct' => false]);

-1

尽管这是一个旧的问题,但在谷歌搜索“doctrine left join limit”时得分很高。很快我就开始寻找“doctrine paginator”,并坚持认为这就是我要找的(而不是doctrine pagination),但我仍然有些困难弄清楚如何使用它。

也许我搜索错了,但实际上找不到关于paginator对象的好文档。无论如何,为了获得结果,我使用了getIterator,这很好用。

我的代码包含包含rss链接的Sources和来自rss源的文章Articles。因此,在这个例子中,我将获取一个Source及其所有文章。这段代码来自Symfony。

        // get the articles (latest first) from source 743
        $q=$this->getDoctrine()->getManager()
          ->createQuery('select s, a from MyCompanyRssBundle:Source s 
          join s.Articles a 
          where s.id = :id 
          order by a.id desc')
          ->setParameter('id',743);
        $q->setMaxResults(1);  // this limits Articles to be only 1
                               // when using $q->getResult();
        $sources=new Paginator($q, $fetchJoin = true);
        $sources=$sources->getIterator();
        var_dump($sources[0]->getArticles());

1
@adridev Sources 被设置为 Paginator,然后被创建的 paginator->getIterator 抛弃了(第二次 sources 被覆盖的部分已经被注释掉)。感谢您的回答,如果您有任何建议可以让这个更好,请随意编辑此答案。我已经有一段时间没有使用 Doctrine 了,所以我甚至不确定这个答案是关于什么的。 - HMR
抱歉,我没有看到评论。是我的错。 - adridev

-2

使用查询构建器做了同样的事情,它可以正常工作。也许还有其他问题?

$qb->add('select', 'b, c, ch, g')
   ->add('from', 'Broadcast b')
   ->add('groupBy', 'b.title')
   ->add('where', 'b.imageBig != \'\'')
   ->add('orderBy', 'b.starttime ASC')
   ->setMaxResults(10)
   ->leftJoin('b.category', 'c')
   ->leftJoin('b.channel', 'ch')
   ->leftJoin('b.genre', 'g')

谢谢,我会尝试使用查询构建器。也许只是使用DQL的问题。 - Stephen Watkins
2
这对于获取连接的集合是行不通的。Christian仅具有已获取连接的To-One关联。 - beberlei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接