2016-12-31 24 views
1

我使用doctrine2和symfony3.1Doctrine2:得到一個計數許多關係

我有一個Movie名單,人們可以買到Ticket,使用直接映射到實體一對多的關係

在儀表板,我想顯示電影的列表,並買了每個

我得到的數據門票的數量我想通過這樣

$manager = $this->getDoctrine()->getManager(); 
    $builder = $manager->createQueryBuilder(); 

    $results = $builder 
     ->select('m') 
     ->from('AppBundle:Movie', 'm') 
     ->addSelect($builder->expr()->count('t')) 
     ->leftJoin('m.tickets', 't') 
     ->groupBy('m.id') 
     ->getQuery() 
     ->getResult() 
    ; 

它產生的100部電影,1個請求:

SELECT 
     e0_.title AS title_0, 
     e0_.is_published AS is_published_1, 
     e0_.description AS description_2, 
     e0_.author AS author_3, 
     e0_.director AS director_4, 
     e0_.artist_list AS artist_list_5, 
     e0_.tags_list AS tags_list_6, 
     e0_.creation_time AS creation_time_7, 
     e0_.id AS id_8, 
     COUNT(t1_.id) AS sclr_9, 
     e0_.place_id AS place_id_10, 
     e0_.organization_id AS organization_id_11, 
     e0_.inner_image1_id AS inner_image1_id_12, 
     e0_.inner_image2_id AS inner_image2_id_13, 
     e0_.inner_image3_id AS inner_image3_id_14, 
     e0_.image_id AS image_id_15 
FROM event e0_ 
LEFT JOIN event_occurence e2_ ON e0_.id = e2_.event_id 
LEFT JOIN ticket t1_ ON e2_.id = t1_.occurence_id 
WHERE e0_.organization_id = '956744cb-6f76-4328-8ea5-c9715d762509' 
GROUP BY e0_.id 
LIMIT 100; 

這是完全是我想要在發出SQL請求的期限。

的問題是在ORM方面,該結果是這樣

[ 
    [ movie, nbrTickets], 
    [ movie, nbrTickets], 
    [ movie, nbrTickets], 
] 

我想知道如何給予提示,教義,使nbrTickets成爲直接的Movie性質組織,(目前我要遍歷我自己),同時還在做只1 SQL查詢(我強烈emphasi所以我不想做movie.tickets | length在我的樹枝

答案應該滿足以下要求:

  • 1,只有一個 SQL查詢(=>否則我的頁面顯示100部電影,它會發出,僅這一點,101個查詢)
  • 允許直接從訪問實體內的結果( =>否則如上所述,我已經有一個解決方案,檢索我想要的數據,我有興趣使代碼更貼近ORM)
  • 不檢索太多的數據。

答案「它目前不可能與教義」也是可以接受的。

+1

使用'{{movie.tickets |長度}}'在你的Twig文件中?這似乎是一個簡單的解決方案。或者,也許你需要控制器中的計數器? –

+0

因爲這樣做會觸發n + 1問題https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/,現在這樣做需要執行N個SQL請求來顯示N個電影 –

+0

我在這裏只看到一個解決方案。將結果保存到一個數組中。比你可以通過任何你想要的。所以'getArrayResult()'應該在這裏而不是'getResult()',但是當然你不會得到一個對象。 – user254319

回答

0

目前看來沒有簡單的方法讓它直接在enti中映射TY。你只能做近似解:(其完成工作,但不是優雅)

  • 使用$movie->tickets->count()這是優雅的,但過於昂貴的(你做的每部電影1多個SQL請求)使用
  • 一個addSelect(我目前的解決方案),它請求獲取所有數據,但需要額外的代碼來映​​射實體中的計數。

似乎有在原則1中的解決方案,解釋here,你能夠從它似乎不再是這樣的實體內訪問包含非映射值的特殊屬性$this->_values

1

您需要正確的註釋才能在電影和票務實體中工作。

電影實體:

* One user has Many tickets. 
* @ORM\OneToMany(targetEntity="Ticket", mappedBy="user") 
*/ 
private $tickets; 

票務實體:

* Many tickets have One movie. 
* @ORM\ManyToOne(targetEntity="movie", inversedBy="tickets") 
* @ORM\JoinColumn(name="movie_id", referencedColumnName="id") 
*/ 
private $movie; 

對於需要在構造函數中定義數組集合的關係

public function __construct() { 
    $this->tickets = new ArrayCollection(); 
} 

你需要創建一個getTickets功能爲這樣的電影實體:

* tickets 
* 
* @return arrayCollection 
*/ 
public function getTickets() 
{ 
    return $this->tickets; 
} 

然後你用下面的庫調用檢索的電影:

$movies = $this->getDoctrine() 
     ->getRepository('AppBundle:movies') 
     ->findAll(); 

最後你獲取門票:

$tickets = $movies[0]->getTickets() 

和你指望他們:

$tickets->count() 
+0

不幸的是,這已經是我(我應該精簡它)。這將發出一個計數請求pert電影,所以如果我顯示最暢銷電影的前100名,現在我的網頁發出101查詢。 –

+0

我已經更新了我的問題,以便更清楚我要找的內容。 –