如何对 findAll Doctrine 的方法进行排序?

Posted

技术标签:

【中文标题】如何对 findAll Doctrine 的方法进行排序?【英文标题】:How to sort findAll Doctrine's method? 【发布时间】:2013-06-11 14:22:17 【问题描述】:

我一直在阅读 Doctrine 的文档,但我一直无法找到对 findAll() 结果进行排序的方法。

我正在使用 symfony2 + 学说,这是我在控制器中使用的语句:

$this->getDoctrine()->getRepository('MyBundle:MyTable')->findAll();

但我希望按用户名升序排列结果。

我一直在尝试以这种方式将数组作为参数传递:

findAll( array('username' => 'ASC') );

但它不起作用(它也不抱怨)。

有什么方法可以在不构建 DQL 查询的情况下做到这一点?

【问题讨论】:

【参考方案1】:

正如@Lighthart 所示,是的,这是可能的,尽管它给控制器增加了大量的脂肪并且不是 DRY。

您真的应该在实体存储库中定义自己的查询,这是简单且最佳的做法。

use Doctrine\ORM\EntityRepository;

class UserRepository extends EntityRepository

    public function findAll()
    
        return $this->findBy(array(), array('username' => 'ASC'));
    

然后您必须告诉您的实体在存储库中查找查询:

/**
 * @ORM\Table(name="User")
 * @ORM\Entity(repositoryClass="Acme\UserBundle\Entity\Repository\UserRepository")
 */
class User

    ...

最后,在您的控制器中:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findAll();

【讨论】:

这个方法比我的好,但是你会写dql;我的方法具有较少的 dql,因此回答了 OP 的约束。坦率地说,应该克服对 dql 的恐惧。如果可能,请优先使用此方法进行挖掘。 好吧,它并不害怕dql,在阅读这个答案之前,我最终使用了DQL来实现这一点,但我一开始不想使用DQL,因为我的控制器中没有任何DQL ,我想坚持控制器已有的代码风格。这个解决方案对我来说非常有用! 或者简单地说:$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(array(), array('username' => 'ASC')); @Benji_X80 虽然那条线肯定更短,但它一点也不干。 findAll 方法属于存储库,而不是控制器。 除了使用 cmets 之外,您能否告诉实体在自定义存储库中查找查询?这是我见过的最糟糕的编程实践【参考方案2】:
$this->getDoctrine()->getRepository('MyBundle:MyTable')->findBy([], ['username' => 'ASC']);

【讨论】:

【参考方案3】:

简单:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(
    array(),
    array('username' => 'ASC')
);

【讨论】:

这就像一个魅力! Symfony 4 仍然以这种方式工作【参考方案4】:

有时查看源代码很有用。

例如findAll实现很简单(vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php):

public function findAll()

    return $this->findBy(array());

所以我们查看 findBy 并找到我们需要的 (orderBy)

public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)

【讨论】:

【参考方案5】:

这对我有用:

$entities = $em->getRepository('MyBundle:MyTable')->findBy(array(),array('name' => 'ASC'));

保持第一个数组为空会取回所有数据,这在我的情况下有效。

【讨论】:

【参考方案6】:

查看 Doctrine API 源代码:

class EntityRepository
  ...
  public function findAll()
    return $this->findBy(array());
  
  ...

【讨论】:

【参考方案7】:

你需要使用一个条件,例如:

<?php

namespace Bundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\Common\Collections\Criteria;

/**
* Thing controller
*/
class ThingController extends Controller

    public function thingsAction(Request $request, $id)
    
        $ids=explode(',',$id);
        $criteria = new Criteria(null, <<DQL ordering expression>>, null, null );

        $rep    = $this->getDoctrine()->getManager()->getRepository('Bundle:Thing');
        $things = $rep->matching($criteria);
        return $this->render('Bundle:Thing:things.html.twig', [
            'entities' => $things,
        ]);
    

【讨论】:

【参考方案8】:

Symfony 中的 findBy 方法除了两个参数。第一个是您要搜索的字段数组,第二个数组是排序字段及其顺序

public function findSorted()
    
        return $this->findBy(['name'=>'Jhon'], ['date'=>'DESC']);
    

【讨论】:

您能否为您的简短回答添加一些解释? 这是一个非常简短的回答。详细说明 - 解释... 编辑. 那是完美的答案! findBy(array(), array('fieldname' => 'ASC') 这将找到所有并按照指示的方向对字段进行排序。【参考方案9】:

您可以使用数组迭代器对现有的 ArrayCollection 进行排序。

假设 $collection 是 findAll() 返回的 ArrayCollection

$iterator = $collection->getIterator();
$iterator->uasort(function ($a, $b) 
    return ($a->getPropery() < $b->getProperty()) ? -1 : 1;
);
$collection = new ArrayCollection(iterator_to_array($iterator));

这可以很容易地变成一个函数,你可以放入你的存储库中,以便创建 findAllOrderBy() 方法。

【讨论】:

你的意思是什么?这有足够多的用例......即在 PHP 中对已经获取的集合进行排序总是比只为排序执行另一个 mysql 查询要快!想象一下,您需要在一页上以两种不同的排序方式输出相同的集合数据... 一般来说,返回一个有序的查询应该是数据库的工作。 OTOH,这种技术确实适用于 nifr 提到的更多涉及的案例。【参考方案10】:

试试这个:

$em = $this->getDoctrine()->getManager();

$entities = $em->getRepository('MyBundle:MyTable')->findBy(array(), array('username' => 'ASC'));

【讨论】:

【参考方案11】:

我使用了编写 nifr 的解决方案的替代方案。

$resultRows = $repository->fetchAll();
uasort($resultRows, function($a, $b)
    if ($a->getProperty() == $b->getProperty()) 
        return 0;
    
    return ($a->getProperty()< $b->getProperty()) ? -1 : 1;
);

它比 ORDER BY 子句更快,而且没有迭代器的开销。

【讨论】:

请为您的答案添加一些进一步的解释。如何在您的应用程序中进行排序比在数据库级别进行排序更快?【参考方案12】:

像这样修改EntityRepository中的默认findAll函数:

public function findAll( array $orderBy = null )

    return $this->findBy([], $orderBy);

这样,您可以在任何数据表的任何查询中使用“findAll”,并可选择对查询进行排序

【讨论】:

以上是关于如何对 findAll Doctrine 的方法进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

使用doctrine中的findAll选择不同的结果

带有 findAll() 方法的 Knp 分页器

Doctrine 存储库返回空结果集

如何在 Doctrine 中使用 findBy() 对结果进行排序

避免 Doctrine 返回完整的相关实体

可捕获致命错误的 FindAll() 结果:DateTime 类的对象无法转换为字符串