2015-01-08 22 views
8

参照用にプライマリキー以外のフィールドを使用している間に遅延ロードする1対1の双方向リファレンスを作成するためにDoctrine ODMを使用するにはどうすればよいですか?Doctrine ODM OneToOne repositoryMethodを使用した双方向リファレンス

MongoDBにはArticleとArticleMetaDataの2つのコレクションがあります。すべてのArticle資料にはArticleMetaDataがあり、その逆もあります。 (OneToOne双方向関係)従来の理由から、2つのドキュメントタイプは別々のコレクションにする必要があります。両方のコレクションは、Mongo IDに関する知識のない外部システムによって更新されます。しかし、これらのフィールドには、適切なアーティクルとそのメタデータを一致させるために使用できる共有フィールド "groupcode"が含まれています。

記事オブジェクトとアーティクルのメタデータをメタデータオブジェクトから取得できるようにDoctrineを設定しようとしていますが、それらをレイジーにロードしておきたいものです。 (私はそれを必要としないもう一方の端を照会する必要はありません。)以下のように

マッピングを見て:

Foo\BarBundle\Document\Article: 
    repositoryClass: Foo\BarBundle\Repository\ArticleRepository 
    changeTrackingPolicy: DEFERRED_EXPLICIT 
    collection: article 
    type: document 
    fields: 
     id: 
      id: true 
     groupcode: 
      type: int 
      index: true 
      unique: 
       order: asc 
     ... 
    referenceOne: 
     metaData: 
      targetDocument: Foo\BarBundle\Document\ArticleMetaData 
      mappedBy: groupcode 
      repositoryMethod: findOneByArticle 

Foo\BarBundle\Document\ArticleMetaData: 
    repositoryClass: Foo\BarBundle\Repository\ArticleMetaDataRepository 
    changeTrackingPolicy: DEFERRED_EXPLICIT 
    collection: article_meta 
    fields: 
     id: 
      id: true 
     groupcode: 
      type: int 
      index: true 
      unique: 
       order: asc 
     ... 
    referenceOne: 
     article: 
      targetDocument: Foo\BarBundle\Document\Article 
      mappedBy: groupcode 
      repositoryMethod: findOneByMetaData 

をし、リポジトリの方法は、上述した:

// In the ArticleRepository 
public function findOneByMetaData(ArticleMetaData $metadata) 
{ 
    $article = $this 
     ->createQueryBuilder() 
     ->field('groupcode')->equals($metadata->getGroupcode()) 
     ->getQuery() 
     ->getSingleResult(); 

    $article->setMetaData($metadata); 

    return $article; 
} 

// In the ArticleMetaDataRepository 
public function findOneByArticle(Article $article) 
{ 
    $metaData = $this 
     ->createQueryBuilder() 
     ->field('groupcode')->equals($article->getGroupcode()) 
     ->getQuery() 
     ->getSingleResult(); 

    $metaData->setArticle($article); 

    return $metaData; 
} 

それはすべてかなりうまくいくようです。私はArticleまたはArticleMetaDataを照会して相手側を取得することができます。問題は次のとおりです。これは遅延ロードに見えません。私は記事を照会する場合:

$article = $documentManager 
    ->getRepository('FooBarBundle:Article') 
    ->findOneBy(['groupcode' => 123]); 

クエリの多くが実行されます。

doctrine.INFO: MongoDB query: {"find":true,"query":{"groupcode":123},"fields":[],"db":"development","collection":"article"} 
doctrine.INFO: MongoDB query: {"limit":true,"limitNum":1,"query":{"groupcode":123},"fields":[]} 
doctrine.INFO: MongoDB query: {"limit":true,"limitNum":null,"query":{"groupcode":123},"fields":[]} 
doctrine.INFO: MongoDB query: {"find":true,"query":{"groupcode":123},"fields":[],"db":"development","collection":"article_meta"} 
doctrine.INFO: MongoDB query: {"limit":true,"limitNum":1,"query":{"groupcode":123},"fields":[]} 
doctrine.INFO: MongoDB query: {"find":true,"query":{"groupcode":123},"fields":[],"db":"development","collection":"article"} 
doctrine.INFO: MongoDB query: {"limit":true,"limitNum":1,"query":{"groupcode":123},"fields":[]} 

私が間違って何をしているのですか?上記の制約を持つ、1対1の双方向参照を怠惰に読み込むことができますか?

編集:

ロブ・ホームズの答えを読んだ後、私はこの問題が発生することがありましたリポジトリ方法でテストを削除しました。残念ながら、問題はまだ残っており、1つ(または最大で2つ)が十分であれば、まだ3つのクエリが実行されています。

答えて

1

Doctrine ODMは、参照先のドキュメントをプリフェッチするのではなく、あらかじめレイジーロードします。

あなたの問題は実際にあなたのリポジトリメソッドにあると信じています...例えば、findOneByMetaData関数では、まず$metadata->getArticle()を呼び出してdoctrineにデータベースから記事を読み込むよう要求していますあなたのrepositoryMethodに再度findOneByMetaDataを呼び出します。このため、複数のクエリが表示されます。

あなたfindOneByMetaData機能がより次のようになります。

// In the ArticleRepository 
public function findOneByMetaData(ArticleMetaData $metadata) 
{ 
    $article = $this->createQueryBuilder() 
     ->field('groupcode')->equals($metadata->getGroupcode()) 
     ->getQuery() 
     ->getSingleResult(); 

    $article->setMetaData($metadata); 

    return $article; 
} 

ドクトリンは、記事がまだロードされているかどうかの世話をしますので、試してみて、NULL値をチェックする必要はありません。同じことも、あなたのfindOneByArticle関数にも当てはまります。

これは意味があると思いますが、問題の解決に役立ちます。

+0

はあなたの提案をいただき、ありがとうございます。私はそのような呼び出しが間違っているとあなたが正しいと信じています。残念なことに実際には、違いはありません。私はあなたの改善で私のポストを更新しました。 – Xatoo

1

これはLogger(loggableCursor)が原因で、ログファイルにクエリが重複しています。 たとえば、find() - > limit(1) - > getQuery()を呼び出すと、各呼び出しがログされますが、実際には単一のクエリ要求があります。

さらに詳しい情報:https://github.com/doctrine/mongodb-odm/issues/471#issuecomment-63999514

ODM問題:https://github.com/doctrine/mongodb/issues/151

+0

ありがとうございます。私は前にこの問題を見ていなかった。上記の問題に基づいて、追加のクエリはログに記録されますが、実際には実行されません。しかし、MongoDB自体のログインを有効にすると、すべてのクエリが実際にデータベースに送信されることが確認できます。 – Xatoo

+0

「記事を見つける」と「記事を検索する」という意味ですか、それともすべてのクエリがログにありますか? – ScorpioT1000

+0

3つすべての検索クエリ。 – Xatoo

関連する問題