115

Doctrine 2のすべてのドキュメントを読み終えたばかりで、独自のサンドボックスを開始しました。ほとんどの原則を理解しましたが、まだ質問があり、ドキュメントに完全な説明が見つかりませんでした。

  1. Proxyクラスとは何ですか?
  2. エンティティに対していつ使用する必要がありますか?

私が理解している限り、プロキシクラスは、エンティティに他の機能を追加できるようにするレイヤーを追加しますが、エンティティクラスにメソッド自体を実装する代わりに、プロキシを使用するのはなぜですか?

4

2 に答える 2

160

アップデート

この回答には、プロキシ オブジェクトと部分オブジェクトの違いに関する誤った情報が含まれています。詳細については、@ 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 が使用する内部オブジェクトとして扱うことができます。

エンティティ自体に遅延読み込みを実装できないのはなぜですか?

技術的にはそうかもしれませんが、ランダムなプロキシ オブジェクトのクラスを見てみましょう。汚いコードでいっぱいです、うーん。エンティティにクリーンなコードがあると便利です。

使用例を教えてください。

最新の 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;
    }
}
于 2011-02-07T20:15:25.010 に答える
89

プロキシ

Doctrine プロキシは、エンティティ クラスを拡張して遅延読み込みを提供する単なるラッパーです。

デフォルトでは、Entity Manager に別のエンティティに関連付けられたエンティティを要求すると、関連付けられたエンティティはデータベースから読み込まれず、プロキシ オブジェクトにラップされます。次に、アプリケーションがこのプロキシされたエンティティのプロパティをリクエストするか、メソッドを呼び出すと、Doctrine はデータベースからエンティティをロードします (常にプロキシに知られている ID をリクエストする場合を除く)。

これは、プロキシがエンティティ クラスを拡張するため、アプリケーションに対して完全に透過的に行われます。

Doctrine は、クエリで関連付けを行わないJOINか、フェッチ モードを に設定した場合、関連付けをデフォルトで遅延ロード プロキシとしてハイドレートしますEAGER


どこにでもコメントするのに十分な評判がないため、これを追加する必要があります。

残念ながら、Crozin の回答には誤った情報が含まれています。

次のような 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 ドキュメント

于 2013-07-22T12:01:59.943 に答える