2013-02-13 185 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