6

我将 Symfony 2 PR12 与 Doctrine 2 和 MySQL 一起使用。我有一个存储文章和这些文章视图的数据库:

// ...
class Article {

    /**
     * @orm:Column(type="bigint")
     * @orm:Id
     * @orm:GeneratedValue
     * @var int
     */
    protected $id;

    /**
     * @orm:OneToMany(targetEntity="ArticleView",mappedBy="article")
     * @var ArrayCollection
     */
    protected $views;

    // ...
}

// ...
class ArticleView {

    /**
     * @orm:Column(type="bigint")
     * @orm:Id
     * @orm:GeneratedValue
     * @var int
     */
    protected $id;

    /**
     * @orm:Column(type="bigint",name="DateRead",nullable=true)
     * @var int
     */
    protected $viewDate;

    /**
     * @orm:ManyToOne(targetEntity="Article",inversedBy="views")
     * @var Article
     */
    protected $article;

    // ...
}

例如,我想获取最近浏览的 20 篇文章。我的第一个想法是:

$qb = <instance of Doctrine\ORM\QueryBuilder>;
$qb->select('a')
   ->from('Article', 'a')
   ->join('a.views', 'v')
   ->orderBy('v.viewDate', 'DESC')
   ->groupBy('a.id')
   ->setMaxResults(20)
;

但是,当有多个视图与一篇文章相关联时,order-by/group-by 组合会给出不可预知的排序结果。

这是 MySQL 的预期行为,因为分组是在排序之前处理的,并且在http://www.artfulsoftware.com/infotree/mysqlquerytree.php(聚合 -> 组内聚合)上有针对此问题的原始查询解决方案. 但是我不知道如何将这些解决方案中的任何一个转换为 DQL,因为据我所知,没有办法从子查询中进行选择或执行自排除连接。

关于如何以合理的性能解决问题的任何想法?

4

1 回答 1

8

我最终用一个相关的子查询来解决它:

$qb
    ->select('a')
    ->from('Article', 'a')
    ->join('a.views', 'v')
    ->orderBy('v.viewDate', 'DESC')
    ->setMaxResults(20)

    // Only select the most recent article view for each individual article
    ->where('v.viewDate = (SELECT MAX(v2.viewDate) FROM ArticleView v2 WHERE v2.article = a)')

这样,排序会忽略 ArticleView,而不是任何给定文章的最新文章。尽管我的猜测是,相对于其他原始 SQL 解决方案,它的性能相当差 - 任何具有更好性能的答案仍然将不胜感激:)。

于 2011-04-29T18:48:44.643 回答