2013-08-28 84 views
3

我想優化查詢,因爲我需要一個簡單的列表作爲附屬於幾個實體的實體。 所以我創造了這個查詢,你應該給我回的ID和名稱:在控制器原則部分查詢返回完整的對象

public function findAllOrderByName() { 
    $qb = $this->createQueryBuilder('a'); 
     $query = $qb->select(array('partial a.{id,name}')) 
       ->addOrderBy('a.name', 'ASC') 
       ->getQuery(); 

     return $query->getResult(); 
} 

換來的卻是這樣的:

public function getInstrumentsAction() 
{ 
    $instruments = $this->getDoctrine()->getRepository('AcmeInstrumentBundle:Instrument')->findAllOrderByName(); 

    return array('instruments' => $instruments); 
} 

,而不是僅僅給我回了兩大陣營,給我完整的對象,因此包括其他相關實體的所有字段。

它爲什麼不起作用?

回答

5

它實際上完全按照設計工作。你正在觀察的是你的相關實體的延遲加載。

開始加入:

echo $query->getSQL() . "\n"; 
return $query->getResult(); 

你看是這樣的:

SELECT p0_.id AS id0, p0_.name AS name1 FROM instrument p0_ ORDER BY p0_.name ASC 

因此,只有兩個你要的實際上被查詢的字段。

echo sprintf("Instrument %s %s %s\n", 
    $instrument->getName(),$instrument->getSomeotherScalervalue()); 

您將會看到雖然名稱被回顯,但其他值卻不在儀器表中。

就關係而言,讓我們假設儀器與人有一對多的關係。

$persons = $instrument->getPersons(); 

你會希望$ persons是一個空數組,但它實際上是一個相當聰明的Doctrine \ ORM \ PersistentCollection。只要你試圖用$ person做任何事情(甚至像count($ persons)這樣簡單的事情),另一個查詢就會被觸發,所有鏈接的person對象將被加載。實際上可以在日誌/ dev.log中看到查詢,只要你插入儀器就會生成一個查詢,只要你嘗試用關係做某件事,另一個查詢就會消失。變通

  1. 不要試圖訪問關係。

  2. 在訪問關係之前,您可以執行$ persons-> setInitialized(true);這將防止加載。顯然有點痛苦。

  3. 由於優化是你的目標,那麼就返回一個數組結果。根本沒有任何物體。

  4. 您也可以繼續並在查詢中加入您的關係,但使用partial來引入相關實體的id。你的查詢工作起來有點困難,但你不需要擔心額外的查詢被觸發。

這將是一種很好,如果有某種方式來防止在查詢特定基礎上延遲加載。但如果有的話,我一直無法找到它。

+0

非常感謝您的解釋! 有一件事我不明白..在dev.log其實我看到使用這個查詢: 'SELECT i0_.id AS id0,i0_.name AS name1 FROM Instrument i0_ ORDER BY i0_.name ASC [] [ ]' 但是當我通過對象時,我就是所有關聯實體的信息。 不知何故會通過懶惰加載水合.. 但是,在我看來,雖然我不確定,使用getArrayResult()執行更快,然後邏輯應該已經排除了所有我不需要的數據! – Lughino

+0

不是。在大多數情況下,延遲加載是一件好事。我想你可以爭辯說,使用部分應該禁用延遲加載,但它可能會變得複雜。你可以在教條留言板上打開討論。 – Cerad

+0

感謝您的諮詢! – Lughino