php 如何使用注解在Doctrine 2集合上首先对NULL值进行排序?

wz1wpwve  于 2023-05-05  发布在  PHP
关注(0)|答案(5)|浏览(131)

我有一个项目使用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如何对实体进行排序的问题。但是,他们都没有提到注解。如建议的那样反转符号的技巧,例如在Doctrine 2 Order By ASC and Null values in last中的属性不起作用,因为Doctrine不接受除属性名称和注解中的ASCDESC之外的任何内容。

soat7uwm

soat7uwm1#

这是一个老帖子,但我发现了一个非常简单的解决方案,如果你正在使用教义查询构建器:

$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方式,除了速度较慢,避免使用偏移量(例如无限滚动)
感谢https://stackoverflow.com/a/23420682/6376420

vsnjm48y

vsnjm48y2#

**可能不会。**有一个SQL语法允许ORDER BY column DESC NULLS FIRST。然而,并不是所有的数据库供应商都支持它,因此如果我正确地扫描了合并请求,它就不是merged into DQL。根据您使用的数据库平台,您可能会很幸运。合并请求中的注解提供了如何在不同的点扩展Doctrine以实现行为的见解,也许这有助于您自己完成它。

np8igboo

np8igboo3#

我的解决方法是创建一个额外的选择到查询中,并从结果数组集合中提取实体,最好只在查询时检查它,而不选择它(以保持结果数组的完整性),但我还没有找到合适的解决方案(使用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());
ryhaxcpt

ryhaxcpt4#

我遇到了同样的问题,这是我的方法:
如果我们不是在谈论大量的处理,你可以使用自定义排序,我需要根据用户的选择,在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得到结果时,你首先会得到NULL,然后你会得到你原来的排序。如果它是ASC,它将保持ASC,反之亦然。
如果在结尾需要NULL值,您只需将第一个“if”更改为相反的符号。
我知道这个问题已经回答了,但我想我可能会把这个留在这里,以防它帮助别人。

yuvru6vn

yuvru6vn5#

在字段检查之前加上(-),使距离为负,那么空值将是最后一个。u将得到负距离值,使用obs()函数从结果中删除(-)。

$repository = $em->getRepository('App\Auth\Entity\User');
      $query = $repository->createQueryBuilder('u')
        ->addSelect('u.id,u.fname,u.lname, - (u.filed_one + :param1) as  distance')
        ->orderBy('distance',"desc")
        ->setParameter('param1', $param1)
        ->getQuery();

相关问题