如何使用具有比较标准的 findBy 方法

Posted

技术标签:

【中文标题】如何使用具有比较标准的 findBy 方法【英文标题】:How to use a findBy method with comparative criteria 【发布时间】:2013-01-25 01:36:27 【问题描述】:

我需要使用使用比较标准(不仅是精确标准)的“魔术查找器”findBy 方法。换句话说,我需要做这样的事情:

$result = $purchases_repository->findBy(array("prize" => ">200"));

这样我就能得到所有奖金超过 200 的购买。

【问题讨论】:

如果您认为教义或 symfony 不是您的菜,那么您只是为您的项目选择了错误的框架。这些框架确实适用于许多项目。 为什么要这么神秘 【参考方案1】:

您必须使用DQL 或QueryBuilder。例如。在您的购买中-EntityRepository 您可以执行以下操作:

$q = $this->createQueryBuilder('p')
          ->where('p.prize > :purchasePrize')
          ->setParameter('purchasePrize', 200)
          ->getQuery();

$q->getResult();

对于更复杂的场景,请查看Expr() class。

【讨论】:

避免在非绝对必要的情况下使用 DQL。它将您锁定在特定于 ORM 的 API 中,并且不能真正重用。在某些情况下需要 DQL,但这不是其中之一。 如何使用 QueryBuilder 不会以完全相同的方式将您锁定在教义中?【参考方案2】:

这是一个使用 Expr() Class 的示例 - 几天前我也需要这个,我花了一些时间来找出确切的语法和使用方式:

/**
 * fetches Products that are more expansive than the given price
 * 
 * @param int $price
 * @return array
 */
public function findProductsExpensiveThan($price)

  $em = $this->getEntityManager();
  $qb = $em->createQueryBuilder();

  $q  = $qb->select(array('p'))
           ->from('YourProductBundle:Product', 'p')
           ->where(
             $qb->expr()->gt('p.price', $price)
           )
           ->orderBy('p.price', 'DESC')
           ->getQuery();

  return $q->getResult();

【讨论】:

如果不是严格需要,请避免使用 DQL,它只会让您的逻辑越来越多地与 ORM 耦合。 @Sliq 这是一种教条行为,不一定与 symfony 有任何关系。 @Sliq 在你尝试了更多的框架之后,你会发现 Symfony 并没有那么糟糕 如果我没看错的话,这个函数是一个存储库方法。在这里,您可以通过 EntityManager 直接访问$this->createQueryBuilder('p'),而不是四处走动:$this->getEntityManager()->createQueryBuilder()【参考方案3】:

Doctrine\ORM\EntityRepository 类实现了Doctrine\Common\Collections\Selectable API。

Selectable 接口非常灵活且非常新,但它允许您在存储库和单个项目集合上轻松处理比较和更复杂的标准,无论是在 ORM 或 ODM 中还是完全独立的问题。

这将是您刚刚在 Doctrine ORM 2.3.2 中要求的比较标准:

$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where(\Doctrine\Common\Collections\Criteria::expr()->gt('prize', 200));

$result = $entityRepository->matching($criteria);

此 API 的主要优点是您在这里实现了某种策略模式,它适用于存储库、集合、惰性集合以及所有实现 Selectable API 的地方。

这使您可以摆脱为存储库编写的数十种特殊方法(例如 findOneBySomethingWithParticularRule),而专注于编写自己的标准类,每个标准类都代表这些特定过滤器之一。

【讨论】:

注意:我正在使用 symfony 2.8.11 和学说 - 也许就在那里 - 它是“Criteria::expr()->gt()”,而不是“$criteria->expr() ->gt()"。 这是一个静态方法:github.com/doctrine/collections/blob/… 另外:Symfony 是 NOT 原则。使用教义名称和版本来参考教义内容:-P @Ocramius 那么理想情况下应该是$criteria::expr()->gt(),不是吗? Criteria::expr() 也可以 - 随时编辑答案。 拥有像 findOneBySomethingWithParticularRule 这样的具体存储库方法是 IMO 的一件好事,因为它将您的业务逻辑与标准构建器等 Doctrine 实现细节分离。【参考方案4】:

Symfony 文档现在明确显示了如何做到这一点:

$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
    'SELECT p
    FROM AppBundle:Product p
    WHERE p.price > :price
    ORDER BY p.price ASC'
)->setParameter('price', '19.99');    
$products = $query->getResult();

来自http://symfony.com/doc/2.8/book/doctrine.html#querying-for-objects-with-dql

【讨论】:

【参考方案5】:
$criteria = new \Doctrine\Common\Collections\Criteria();
    $criteria->where($criteria->expr()->gt('id', 'id'))
        ->setMaxResults(1)
        ->orderBy(array("id" => $criteria::DESC));

$results = $articlesRepo->matching($criteria);

【讨论】:

这对我不起作用,请参阅***.com/questions/49450970/…【参考方案6】:

我喜欢使用这样的静态方法:

$result = $purchases_repository->matching(
    Criteria::create()->where(
        Criteria::expr()->gt('prize', 200)
    )
);

当然,当条件为1的时候你可以push逻辑,但是当你有更多的条件时,最好将它分成片段,配置并传递给方法:

$expr = Criteria::expr();

$criteria = Criteria::create();
$criteria->where($expr->gt('prize', 200));
$criteria->orderBy(['prize' => Criteria::DESC]);

$result = $purchases_repository->matching($criteria);

【讨论】:

以上是关于如何使用具有比较标准的 findBy 方法的主要内容,如果未能解决你的问题,请参考以下文章

如何使用findBy ..()方法为一条记录编写查询

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

如何在 Selenium 中使用 @FindBy 注释来处理跨度文本?

如何在JPQL中创建“findBy Date”命名查询?

具有多个 in 运算符的 crudrepository findBy 方法签名?

如何使用 findBy($creteria) 进行双向 OneToOne 映射?