2013-02-13 168 views
2

我有一个OneToMany关系,一个足球队有很多球员。我想列出所有的足球队并显示每个队的队长名字。Symfony2 +学说 - 过滤

每个玩家的实体有一个外键(TEAM_ID)和被设置为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(); 
} 

有没有更好的方式来运行此查询?

回答

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() 

然后你换这个查询到对象(因为setMaxResultssetFirstResultcannot 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"; 
} 

您也可以通过获得在getTeamCaptain方法一些额外的性能Selectable API

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

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

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

这样做的优点是当联想players尚未初始化主要是相关的,因为这将避免加载它完全。事实并非如此,但我认为这是一个好习惯(而不是重新设计收集过滤逻辑)。

+0

对于那些被这个答案困惑的人来说:最后一个答案回答了提出的具体问题,其余的答案都是关于改善需要改进的情况,但实际上并没有被问到。 – Lighthart 2013-02-14 00:53:51

+0

@Lighthart:不,用户要求一种优化逻辑的方法。他的初始版本产生了'N * M + 1'查询,因为'Team#players'集合的延迟初始化,然后是这些集合中的单个玩家,以检查'player.captain == 1'。仅优化'getTeamCaptain'仍然会导致'N + 1'查询初始化集合。获取 - 加入“Team#players”集合可以将所有这些逻辑缩减为“1”单个查询。 因此,仅在这里优化'getTeamCaptain'远远不够。 – Ocramius 2013-02-14 00:58:18

+0

paginator与此无关。 – Lighthart 2013-02-14 00:59:27