[英]How can I order NULL values first on a Doctrine 2 collection using annotations?
我有一个使用Symfony 2并包含Doctrine 2实体的项目。 其中一些实体彼此相关。 此关联由注释定义:
/**
* @ORM\OneToMany(targetEntity="Event", mappedBy="firstEntityId" cascade={"persist", "remove"})
* @ORM\OrderBy({"dateEnd" = "DESC", "dateBegin" = "DESC"})
*/
private $events;
如您所见,此关联包含多个具有开始日期和结束日期的事件。 在检索此集合时,我希望最多的事件(即那些尚未结束或最近结束的事件)先排序。
当前方法的问题在于它将在所有其他事件之后对结束日期为NULL
事件进行排序。
如何告诉Doctrine首先对结束日期为NULL
的事件进行排序,然后按降序结束日期对剩余事件进行排序?
到目前为止,我已经看到了几个关于如何告诉Doctrine如何订购实体的问题。 但是,他们都没有提到注释。 例如在Doctrine 2 Order By ASC中建议的反转符号的技巧和最后的Null值不起作用,因为Doctrine在注释中不接受除属性名称和ASC
或DESC
之外的任何内容。
这是一篇旧帖子,但如果你使用的是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的方式,除了慢一点,避免使用偏移(例如无限滚动)
可能不是。 有一种SQL语法允许ORDER BY column DESC NULLS FIRST
。 但是,并非所有数据库供应商都支持它,因此如果我正确扫描了合并请求,则尚未合并到DQL中 。 根据您使用的数据库平台,您可能会很幸运。 合并请求中的注释提供了如何在不同点扩展Doctrine以实现行为的洞察力,这可能有助于您自己完成。
我有同样的问题,这是我的方法:
如果我们不是在谈论大量的处理,你可以使用自定义排序,我需要根据用户选择将结果按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值,您只需要将第一个'if'更改为相反的符号。
我知道这个问题已经回答了,但我想我可以把它放在这里以防它帮助其他人。
我的解决方法是创建为查询添加一个额外的选择并从结果数组集合中提取实体,最好只在查询时检查它而不选择它(保持结果数组完整)但我还没有找到了一个合适的解决方案(使用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());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.