8

エンティティとCar多対1の関係にあるエンティティがありますOwner。すべての車を選択すると、Doctrineはテーブルに対してCar1つのクエリを実行し、続いて車ごとOwnerにテーブルに対して1つのクエリを実行します。したがって、N台の車をフェッチすると、とテーブル間の単一のJOINクエリではなく、N+1クエリになります。CarOwner

私の実体は次のとおりです。

/** @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"は関係ありません。2つのエンティティ間でJOINを使用してカスタムDQLクエリを実行して$car->getOwner()も、Doctrineはデータベースにクエリを実行します(EAGERを使用しない限り、$repo->findAll()すべてのエンティティが発生します)。

私はここで疲れすぎていますか?これはそれが機能するはずの方法です-またはDoctrineに代わりにJOINクエリを実行させる賢い方法はありますか?

4

3 に答える 3

6

少なくとも1.xDoctrineでは、関連するオブジェクトをクエリする場合は、DQLを使用する必要がありました。あなたの場合、DQLクエリは次のようになります。

//Assuming $em is EntityManager
$query = $em->createQuery('SELECT c, o FROM Car c JOIN c.owner o');
$cars = $query->execute();
于 2010-11-12T18:45:45.317 に答える
4

最初に、所有者と参加しているすべての車(DQL JOIN)を選択するDQLクエリを実行します。所有者をに入れ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一般ログ)

于 2013-09-03T11:00:36.883 に答える
1

あなたの質問...

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

...はforeachループ内にあるため、確実にクエリを数回発行します。

これに対処するためにカスタムDQLを作成している場合は$car->getOwner()、これをまったく取り上げないでください。これはCarクラスの機能です。作成するカスタムDQLは、指摘した正確なSQLクエリを模倣し、結合を効率的に実行します。

于 2010-11-12T19:18:46.987 に答える