我正在使用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处有针对此问题的原始查询解决方案(聚合 - &gt;组内聚合)。但我无法弄清楚如何将这些解决方案转换为DQL,因为据我所知,无法从子查询中选择或执行自我排除连接。
关于如何以合理的性能解决问题的任何想法?
答案 0 :(得分: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,而不是最新的ArticleView。虽然我的猜测是,相对于其他原始SQL解决方案而言,它的表现相当差 - 任何具有更好性能的答案仍然会受到高度赞赏:)。