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

Cha*_*yer 6 php symfony doctrine-orm

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

例如,假设我有一个$view具有此定义的实体:

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

public function getVersions() {
    return $this->versions;
}
Run Code Online (Sandbox Code Playgroud)

我希望得到与实体相关的所有版本,如下所示:

$view->getVersions();
Run Code Online (Sandbox Code Playgroud)

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

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

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

Rya*_*yan 9

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

它似乎没有名称,但您可以在9.8过滤集合的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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这将做两件事之一:

  1. 如果集合是水合的,它将使用PHP来过滤现有的集合.
  2. 如果集合没有水合,它将使用SQL约束从数据库中获取部分集合.

这真的很棒,因为将存储库方法连接到您的视图通常是混乱的并且容易中断.

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


Igo*_*vić 1

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

然而,我不会在那时甚至之前这样做。根据您的具体情况,我将创建一个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

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

$versions = $view->getVersions(); // Will only contain versions newer than datetime provided
Run Code Online (Sandbox Code Playgroud)

我在这里直接从头开始编写代码,如果出现一些语法或方法命名错误,我很抱歉。