Symfony2 + Doctrine - 过滤

时间:2013-02-13 21:19:32

标签: sql symfony doctrine-orm query-optimization dql

我有一个OneToMany关系,其中一个足球队有很多球员。我想列出所有足球队并显示每队的队长名称。

每个玩家实体都有一个外键(team_id)和一个字段'captain',设置为0或1.我正在运行以下查询:

 $teams = $this
             ->getDoctrine()
             ->getRepository('FootballWebsiteBundle:Team')
              ->createQueryBuilder('t')
             ->setFirstResult(($pageNumber * $resultPerPage) - $resultPerPage)
             ->setMaxResults($resultPerPage)
             ->add('where','t.deleted = 0')
             ->add('orderBy', 't.name DESC')
             ->getQuery()->getResult();

然后当我循环遍历每个团队时,我运行team.getTeamCaptain()。getName()这是我的团队实体中的过滤器:

public function getTeamCaptain() {
    $them  = $this->players->filter(function($p) {
        return $p->getCaptain() == 1;
    });

    return $them->first();
}

有更好的方法来运行此查询吗?

1 个答案:

答案 0 :(得分:4)

首先,您可能希望fetch-join每个检索到的团队的玩家避免在渲染模板期间延迟加载它们。这是DQL:

SELECT
    t, p
FROM
    FootballWebsiteBundle:Team t
LEFT JOIN
    t.players p
WHERE
    t.deleted = 0
ORDER BY
    t.name DESC

可以使用以下查询构建器API调用构建:

 $teamsQuery = $this
         ->getDoctrine()
         ->getRepository('FootballWebsiteBundle:Team')
         ->createQueryBuilder('t')
         ->addSelect('p')
         ->leftJoin('t.players', 'p')
         ->add('where','t.deleted = 0')
         ->add('orderBy', 't.name DESC')
         ->getQuery()

然后将此查询包装到Paginator对象中(从setMaxResultssetFirstResult cannot be trusted when fetch-joining开始):

$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($teamsQuery, true);

$teamsQuery
     ->setFirstResult(($pageNumber * $resultPerPage) - $resultPerPage)
     ->setMaxResults($resultPerPage)

在您的视图中,您可以像遵循伪代码一样迭代团队:

foreach ($paginator as $team) {
    echo $team->getTeamCaptain() . "\n";
}

您还可以使用Selectable APIgetTeamCaptain方法中获得额外的性能:

public function getTeamCaptain() {
    $criteria = new \Doctrine\Common\Collections\Criteria();

    $criteria->andWhere($criteria->expr()->eq('captain', 1));

    return $this->players->matching($criteria)->first();
}

此处的优势主要与关联players尚未初始化时相关,因为这样可以避免完全加载它。情况并非如此,但我认为这是一个很好的做法(而不是重新发明集合过滤逻辑)。