Symfony中关联实体集合的高级过滤

时间:2014-05-15 21:30:48

标签: php symfony doctrine-orm

如果我有一个关联的实体是一个集合,你在获取时有什么选择?

e.g。假设我有一个$view实体,其中包含此定义:

/**
 * @ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="entity")
 * @ORM\OrderBy({"timeMod" = "DESC"})
 */
protected $versions;

public function getVersions() {
    return $this->versions;
}

我想得到与这个实体相关的所有版本:

$view->getVersions();

这将返回一个集合。大。但是有可能采取该集合并按标准过滤它,例如比某个日期更新?或者按一些(其他)标准订购?

或者此时您只是希望对存储库进行查询:

$versions = $em->getRepository("GutensiteCmsBundle:View\ViewVersion")->findBy(array(
    array(
        'viewId', $view->getId(),
        'timeMod', time()-3600
    )
    // order by
    array('timeMod', 'DESC')
));

2 个答案:

答案 0 :(得分:9)

最新版本的Doctrine中有一个令人惊讶的未知功能,这使得这些查询变得更加容易。

它似乎没有名称,但您可以在9.8 Filtering Collections的Doctrine文档中了解它。

  

集合具有过滤API,允许从集合中分割部分数据。如果尚未从数据库加载集合,则过滤API可以在SQL级别上工作,以便对大型集合进行优化访问。

在您的情况下,您可以在View实体上编写这样的方法。

use Doctrine\Common\Collections\Criteria;

class View {
  // ...

  public function getVersionsNewerThan(\DateTime $time) {
    $newerCriteria = Criteria::create()
      ->where(Criteria::expr()->gt("timeMod", $time));

    return $this->getVersions()->matching($newerCriteria);
  }
}

这将做以下两件事之一:

  1. 如果集合是水合的,它将使用PHP过滤现有的集合。
  2. 如果集合没有水合,它将使用SQL约束从数据库中获取部分集合。
  3. 这真的很棒,因为将存储库方法连接到您的视图通常很麻烦并且容易中断。

    我也喜欢@ igor-pantovic的回答,虽然我看到这种方法会导致一些有趣的错误。

答案 1 :(得分:1)

我个人会避免直接在注释上使用order by。是的,您应该进行查询,就像您使用没有Doctrine的原始SQL一样。

然而,我不会在那时做,但甚至在此之前。在您的具体情况下,我将创建一个ViewRepository类:

class ViewRepository extends EntityRepository
{
    public function findWithVersionsNewerThan($id, \DateTime $time)
    {
        return $this->createQueryBuilder('view')
            ->addSelect('version')
            ->join('view.versions', 'version')
            ->where('view.id = :id')
            ->andWhere('version.timeMod > :time')
            ->setParameter('time', $time)
            ->setParameter('id', $id)
            ->getQuery()
            ->getOneOrNullResult();
    }
}

现在你可以做到:

$yourDateTime = // Calculate it here ... ;
$view = $em->getRepository("GutensiteCmsBundle:View\ViewVersion")->findWithVersionsNewerThan($yourDateTime);

$versions = $view->getVersions(); // Will only contain versions newer than datetime provided

我正在直接从头顶编写代码,很抱歉,如果某些语法或方法命名错误隐藏在其中。