我有一个使用Symfony 2并包含Doctrine 2实体的项目。其中一些实体彼此相关。此关联由注释定义:
/**
* @ORM\OneToMany(targetEntity="Event", mappedBy="firstEntityId" cascade={"persist", "remove"})
* @ORM\OrderBy({"dateEnd" = "DESC", "dateBegin" = "DESC"})
*/
private $events;
如您所见,此关联包含多个具有开始日期和结束日期的事件。在检索此集合时,我希望最多的事件(即那些尚未结束或最近结束的事件)先排序。
当前方法的问题在于,它会在所有其他事件之后对结束日期为NULL
的事件进行排序。
如何告诉Doctrine首先对结束日期为NULL
的事件进行排序,然后按结束日期降序对其余事件进行排序?
ASC
或DESC
以外的任何内容。
答案 0 :(得分:7)
这是一篇旧帖子,但如果您使用的是doctrine查询构建器,我发现了一个非常简单的解决方案:
$sortDirection = 'ASC';
$qb = $this->createQueryBuilder('e');
$qb->addSelect('CASE WHEN e.valueToOrder IS NULL THEN 1 ELSE 0 END AS HIDDEN myValueIsNull');
//other stuffs
//$qb->where ...
$qb->orderBy('myValueIsNull','ASC');
$qb->addOrderBy('e.valueToOrder',':sortDirection');
$qb->setParameter(':sortDirection',$sortDirection);
return $qb->getQuery()->getResult();
PHP方式,除了慢一点,避免使用偏移(例如无限滚动)
答案 1 :(得分:3)
可能不是。有一种允许ORDER BY column DESC NULLS FIRST
的SQL语法。但是,并非所有数据库供应商都支持它,因此如果我正确扫描了合并请求,则不是merged into DQL。根据您使用的数据库平台,您可能会很幸运。合并请求中的注释提供了如何在不同点扩展Doctrine以实现行为的洞察力,也许这可以帮助您自己完成。
答案 2 :(得分:1)
我遇到了同样的问题,这是我的方法:
如果我们不是在谈论大量处理,您可以使用自定义排序,我需要根据用户选择将结果按asc或desc中的列排序。但是,我还需要首先出现相同列的空值。因此,经过大量谷歌搜索NULLS FIRST方法后,我决定在从查询构建器中获得结果后立即进行操作:
// Custom sort to put the nulls first
usort($invoices, function(Entity $a, Entity $b) use ($order) {
if(null === $a->getNumber())
return -1;
if(null === $b->getNumber())
return 1;
if(strtoupper($order) == "DESC") {
if($a->getNumber() > $b->getNumber())
return -1;
if($b->getNumber() > $a->getNumber())
return 1;
} else {
if($a->getNumber() < $b->getNumber())
return -1;
if($b->getNumber() < $a->getNumber())
return 1;
}
});
这样,当您从QueryBuilder获得结果时,您将首先获得NULLS,然后您将获得原始排序。如果它是ASC,它将保持ASC,反之亦然。
如果最后需要NULL值,您只需更改第一个&#39; if&#39;相反的迹象。
我知道这个问题已经回答了,但我想我可以把它放在这里,以防它帮助其他人。
答案 3 :(得分:1)
我的解决方法是创建为查询添加一个额外的select并从结果数组中提取实体,最好只在查询时检查它而不选择它(保持结果数组完整)但我还没有找到适当的解决方案(使用QueryBuilder
)。
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
$queryBuilder->select('e')
->from(Entity::class, 'e')
// We use ZZZZ here as placeholder to push the null values last, use 'AAAA' to sort them first.
->addSelect('CASE WHEN(e.name IS NULL) THEN \'ZZZZ\' ELSE e.name END AS name')
->addOrderBy('name', 'ASC');
// As we have a array result due to the "addSelect()" above, we must extract the entities now, in this example by looping over the result array.
$entities = array_map(function ($contributor) {
return $contributor[0];
}, $queryBuilder->getQuery()->getResult());