簡體   English   中英

Doctrine2多對一關聯不會使用JOIN查詢

[英]Doctrine2 many-to-one association won't use JOIN query

我有一個與實體Owner多對一關系的Car實體。 如果我選擇所有汽車,Doctrine會在Car表上執行一次查詢,然后在Owner表上對每輛汽車進行一次查詢。 因此,獲取N個汽車變為N + 1個查詢,而不是CarOwner表之間的單個JOIN查詢。

我的實體如下:

/** @Entity */
class Car {

  /** @Id @Column(type="smallint") */
  private $id;

  /** @ManyToOne(targetEntity="Owner", fetch="EAGER")
      @JoinColumn(name="owner", referencedColumnName="id") */
  private $owner;

  public function getId()    { return $this->id; }
  public function getOwner() { return $this->owner; }
}

/** @Entity */
class Owner {

  /** @Id @Column(type="smallint") */
  private $id;

  /** @Column(type="string") */
  private $name;

  public function getName() { return $this->name; }
}

如果我想與他們的車主列出汽車,我會這樣做:

$repo = $em->getRepository('Car');
$cars = $repo->findAll();

foreach($cars as $car) 
  echo 'Car no. ' . $car->getId() . 
       ' owned by ' . $car->getOwner()->getName() . '\n';

現在這一切都很有效,除了Doctrine為每輛車發出查詢這一事實。

SELECT * FROM Car;
SELECT * FROM Owner WHERE id = 1;
SELECT * FROM Owner WHERE id = 2;
SELECT * FROM Owner WHERE id = 3;
....

當然我希望我的查詢日志看起來像這樣:

SELECT * FROM Car JOIN Owner ON Car.owner = Owner.id;

我是否有fetch="EAGER"fetch="LAZY"並不重要,即使我在兩個實體之間使用JOIN進行自定義DQL查詢, $car->getOwner()仍會導致Doctrine查詢數據庫(除非我使用EAGER,在這種情況下$repo->findAll()導致所有這些)。

我在這里太累了,這是它應該工作的方式 - 或者是否有一種聰明的方法來迫使Doctrine進行JOIN查詢?

至少在1.x Doctrine中如果要查詢相關對象,則必須使用DQL。 對於您的情況,DQL查詢看起來像這樣:

//Assuming $em is EntityManager
$query = $em->createQuery('SELECT c, o FROM Car c JOIN c.owner o');
$cars = $query->execute();

先運行DQL查詢,然后選擇與所有者聯接的所有汽車(DQL JOIN)。 將所有者放在select()

// preload cars
$qb = $em->createQueryBuilder()
        ->select('car, owner')
        ->from('\Entity\Car', 'car')
        ->leftJoin('c.owner',  'owner');

    $query = $qb->getQuery();

    // the following seems not needed, but I think it depends on the conf
    $query->setFetchMode("\Entity\Car", "owner", "EAGER");

    $query->execute(); //you don't have to use this result here, Doctrine will keep it

然后,Doctrine 2將執行JOIN(通常更快,因為它需要更少的db查詢,具體取決於記錄的數量)。 現在啟動你的foreach ,Doctrine將在內部找到實體,當你需要owner時它不會運行單個查詢。

監控每次更改后的查詢次數(例如,mysql常規日志)

您的查詢...

$car->getOwner() // "go and fetch this car's owner"

...在foreach循環中,因此它肯定會多次發出查詢。

如果你正在編寫自定義DQL來處理這個問題,那么$car->getOwner()就不應該具有這個功能了。 這是Car類的功能。 您要編寫的自定義DQL將模仿您指出的確切SQL查詢並有效地完成連接。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM