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);
}

2つのキャンプを返すだけでなく、他の関連エンティティのすべてのフィールドを含む完全なオブジェクトを提供します。

なぜうまくいかなかったのですか?

4

1 に答える 1

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

したがって、実際に照会されるのは、要求した 2 つのフィールドだけです。

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

name がエコーされている間、instrument テーブルにあるにもかかわらず、他の値がエコーされていないことがわかります。

関係に関する限り、instrument が person に対して oneToMany 関係を持っているとしましょう。

$persons = $instrument->getPersons();

$persons が空の配列であると予想するかもしれませんが、実際にはかなりスマートな Doctrine\ORM\PersistentCollection です。$person (count($persons) のような単純なことでも) で何か他のことをしようとするとすぐに、別のクエリがトリガーされ、リンクされたすべての人物オブジェクトが読み込まれます。

それがあなたが見ているものです。実際には、logs/dev.log でクエリを確認できます。機器を引き込むだけで、クエリは 1 つだけ生成されます。リレーションで何かをしようとするとすぐに、別のクエリが出てきます。

回避策

  1. リレーションにアクセスしようとしないでください。

  2. リレーションにアクセスする前に、 $persons->setInitialized(true); を実行できます。それはロードを防ぎます。明らかに少し痛い。

  3. 最適化が目標な​​ので、配列の結果を返すだけです。オブジェクトはまったくありません。

  4. 先に進んでクエリで関係を結合することもできますが、partial を使用して、関連するエンティティの ID を入力するだけです。クエリは少し難しくなりますが、追加のクエリがトリガーされることを心配する必要はありません。

クエリ固有のベースで遅延読み込みを防ぐ方法があれば、ちょっといいでしょう。しかし、もしあれば、私はそれを見つけることができませんでした.

于 2013-08-28T21:59:12.283 に答える