回答:
更新
この回答には、プロキシオブジェクトと部分オブジェクトの違いに関する誤った情報が含まれています。詳細については@Kontrollfreakの回答を参照してください:https : //stackoverflow.com/a/17787070/252591
クエリがエンティティの作成に必要なすべてのデータを返さない場合は常に、プロキシオブジェクトが使用されます。次のシナリオを想像してみてください:
@Entity
class User {
@Column protected $id;
@Column protected $username;
@Column protected $firstname;
@Column protected $lastname;
// bunch of setters/getters here
}
DQL query:
SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id
あなたが見ることができるように、このクエリは返さないfirstname
とlastname
性質は、したがって、あなたが作成することはできませんUser
オブジェクトを。不完全なエンティティを作成すると、予期しないエラーが発生する可能性があります。
それがDoctrineがUserProxy
遅延読み込みをサポートするオブジェクトを作成する理由です。firstname
(読み込まれていない)プロパティにアクセスしようとすると、最初にデータベースからその値が読み込まれます。
なぜプロキシを使用する必要があるのですか?
プロキシオブジェクトをまったく使用しなかったかのように、常にコードを記述する必要があります。それらはDoctrineが使用する内部オブジェクトとして扱うことができます。
Entitiy自体に遅延読み込みを実装できないのはなぜですか?
技術的にはそうかもしれませんが、ランダムなプロキシオブジェクトのクラスを見てみましょう。汚いコードだらけです。エンティティにクリーンなコードを含めるのはいいことです。
ユースケースを教えてもらえますか?
最新の25件の記事のリストを表示していて、最初の記事の詳細を表示したいとします。それぞれに大量のテキストが含まれているため、そのすべてのデータをフェッチするとメモリの浪費になります。これが、不要なデータをフェッチしない理由です。
SELECT a.title, a.createdAt
FROM Entity\Article a
ORDER BY a.createdAt DESC
LIMIT 25
$isFirst = true;
foreach ($articles as $article) {
echo $article->getTitle();
echo $article->getCreatedAt();
if ($isFirst) {
echo $article->getContent(); // Article::content is not loaded so it is transparently loaded
// for this single article.
$isFirst = false;
}
}
Doctrineプロキシは、エンティティクラスを拡張して遅延読み込みを提供するラッパーです。
デフォルトでは、エンティティマネージャーに別のエンティティに関連付けられているエンティティを要求すると、関連付けられているエンティティはデータベースから読み込まれず、プロキシオブジェクトにラップされます。アプリケーションがプロパティをリクエストするか、このプロキシされたエンティティのメソッドを呼び出すと、Doctrineはデータベースからエンティティをロードします(IDをリクエストする場合を除きます。IDは常にプロキシに認識されます)。
これは、プロキシがエンティティクラスを拡張するため、アプリケーションに対して完全に透過的に行われます。
Doctrineはデフォルトで関連付けを遅延ロードプロキシとしてハイドレートJOIN
します。クエリでそれらを指定しないか、フェッチモードをに設定した場合ですEAGER
。
どこにでもコメントできる評判がないので、これを追加する必要があります。
残念ながら、クロジンの回答には誤った情報が含まれています。
次のようなDQLクエリを実行すると
SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id
(プロキシ化された)エンティティオブジェクトではなく、連想配列を取得します。したがって、追加のプロパティを遅延読み込みすることはできません。
これを念頭に置いて、ユースケースの例も機能しないという結論に達します。$article
オブジェクトとしてアクセスするには、DQLを次のように変更する必要があります。
SELECT a FROM Entity\Article a ORDER BY a.createdAt DESC LIMIT 25
25のエンティティすべてgetContent()
のコンテンツプロパティを読み込まないためには、によって返されるプロパティは関連付けである必要があります。
アソシエーションではないエンティティプロパティを部分的にロードしたい場合、このDoctrineに明示的に伝える必要があります:
SELECT partial u.{id, username} FROM Entity\User u WHERE u.id = :id
これにより、部分的に読み込まれたエンティティオブジェクトが得られます。
ただし、部分オブジェクトはプロキシではないことに注意してください。遅延読み込みはそれらには適用されません。したがって、部分オブジェクトの使用は一般的に危険であり、避ける必要があります。続きを読む:部分オブジェクト— Doctrine 2 ORM 2ドキュメント