如何使用注解在 Doctrine 2 集合上首先排序 NULL 值?
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
的事件进行排序,然后按结束日期降序对剩余事件进行排序?
到目前为止,我已经在 SO 上看到了几个关于如何告诉 Doctrine 如何对实体排序的问题。但是,none 其中提到了注释。按照建议反转符号的技巧,例如在 Doctrine 2 Order By ASC and Null values in last 中不起作用,因为 Doctrine 不接受注释中 属性 名称和 ASC
或 DESC
以外的任何内容。
可能不会。 有一个 SQL 语法允许 ORDER BY column DESC NULLS FIRST
。但是,并非所有数据库供应商都支持它,因此如果我正确扫描了合并请求,则不会 merged into DQL。根据您使用的数据库平台,您可能很幸运。合并请求中的评论提供了如何在不同点扩展 Doctrine 以实现行为的见解,也许这有助于您自己完成。
我遇到了同样的问题,这是我的方法:
如果我们不讨论大量处理,您可以使用自定义排序,我需要根据用户选择按 asc 或 desc 列对结果进行排序。但是,我还需要首先出现同一列的空值。因此,在对 NULLS FIRST 方法进行大量谷歌搜索之后,我决定在从查询构建器获得结果后立即进行 usort:
// 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' 更改为相反的符号即可。
我知道这个问题已经回答了,但我想我可能会把它留在这里以防它对其他人有帮助。
我的解决方法是在查询中添加一个额外的 select 并从生成的数组集合中提取实体,最好只在查询时检查它而不是 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());
这是一个旧的 post,但如果您使用的是学说查询生成器,我找到了一个非常简单的解决方案:
$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 方式,除了更慢之外,避免使用偏移量(例如无限滚动)
感谢
我有一个使用 Symfony 2 并包含 Doctrine 2 实体的项目。其中一些实体彼此相关。该关联由注释定义:
/**
* @ORM\OneToMany(targetEntity="Event", mappedBy="firstEntityId" cascade={"persist", "remove"})
* @ORM\OrderBy({"dateEnd" = "DESC", "dateBegin" = "DESC"})
*/
private $events;
如您所见,此关联包含多个具有开始日期和结束日期的事件。检索此集合时,我希望首先对最近发生的事件(即尚未结束或最近结束的事件)进行排序。
当前方法的问题在于它将结束日期为 NULL
的事件排在所有其他事件之后。
如何告诉 Doctrine 先对结束日期为 NULL
的事件进行排序,然后按结束日期降序对剩余事件进行排序?
到目前为止,我已经在 SO 上看到了几个关于如何告诉 Doctrine 如何对实体排序的问题。但是,none 其中提到了注释。按照建议反转符号的技巧,例如在 Doctrine 2 Order By ASC and Null values in last 中不起作用,因为 Doctrine 不接受注释中 属性 名称和 ASC
或 DESC
以外的任何内容。
可能不会。 有一个 SQL 语法允许 ORDER BY column DESC NULLS FIRST
。但是,并非所有数据库供应商都支持它,因此如果我正确扫描了合并请求,则不会 merged into DQL。根据您使用的数据库平台,您可能很幸运。合并请求中的评论提供了如何在不同点扩展 Doctrine 以实现行为的见解,也许这有助于您自己完成。
我遇到了同样的问题,这是我的方法:
如果我们不讨论大量处理,您可以使用自定义排序,我需要根据用户选择按 asc 或 desc 列对结果进行排序。但是,我还需要首先出现同一列的空值。因此,在对 NULLS FIRST 方法进行大量谷歌搜索之后,我决定在从查询构建器获得结果后立即进行 usort:
// 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' 更改为相反的符号即可。
我知道这个问题已经回答了,但我想我可能会把它留在这里以防它对其他人有帮助。
我的解决方法是在查询中添加一个额外的 select 并从生成的数组集合中提取实体,最好只在查询时检查它而不是 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());
这是一个旧的 post,但如果您使用的是学说查询生成器,我找到了一个非常简单的解决方案:
$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 方式,除了更慢之外,避免使用偏移量(例如无限滚动)
感谢