2015-01-08 6 views
8

Wie kann Doctrine ODM verwendet werden, um eine Eins-zu-Eins-bidirektionale Referenz zu erstellen, die bei Verwendung eines anderen Feldes als des Primärschlüssels für die Referenz "Lazy Loads" verwendet?Doctrine ODM OneToOne bidirektionale Referenz mit repositoryMethod

Ich habe zwei Sammlungen in MongoDB mit Dokumenten, Artikel und ArticleMetaData. Für jedes Artikeldokument gibt es eine ArticleMetaData und umgekehrt. (Eine bidirektionale OneToOne-Beziehung.) Aus beiden Gründen müssen die beiden Dokumenttypen in separaten Sammlungen sein. Beide Sammlungen werden von externen Systemen aktualisiert, die keine Kenntnis über die Mongo-IDs haben. Sie enthalten jedoch ein gemeinsames Feld "groupcode", mit dem der richtige Artikel mit seinen Metadaten abgeglichen werden kann.

Ich versuche Doctrine so zu konfigurieren, dass ich die Metadaten für ein Artikelobjekt und einen Artikel aus seinem Metadatenobjekt bekommen kann, aber ich möchte sie faul geladen halten. (Es besteht keine Notwendigkeit für das andere Ende abzufragen, wenn ich es nicht brauchen.)

die Zuordnungen wie folgt aussehen:

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 

Und die Repository-Methoden oben erwähnt:

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

Es scheint alles ganz gut zu funktionieren. Ich kann einen Artikel oder ArticleMetaData abfragen und bekomme die andere Seite, nur Das Problem ist: es scheint nicht zu faul laden. Wenn ich für einen Artikel abfragen:

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

Viele Abfragen ausgeführt werden:

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":[]} 

Was mache ich falsch? Gibt es eine Art und Weise, wie ich eine bidirektionale Referenz mit verzögerter Ladeoperation erreichen kann, die die obigen Einschränkungen aufweist?

Edit:

Nach der Lektüre Rob Holmes' Antwort nahm ich einen Test in den Repository-Methoden, die das Problem verursacht haben könnten. Leider bleibt das Problem bestehen und es werden immer noch 3 Abfragen ausgeführt, wobei eine (oder höchstens zwei) ausreicht.

Antwort

1

Doctrine ODM lädt das referenzierte Dokument bereits, anstatt es für Sie vorab abzurufen.

Ich glaube, dass Ihr Problem tatsächlich in Ihren Repository-Methoden liegt ... Zum Beispiel, in der findOneByMetaData Funktion das erste, was Sie tun, rufen Sie $metadata->getArticle() dabei Sie fragen Doktrin, den Artikel aus der Datenbank laden, was fällig zu Ihrem RepositoryMethode wird wieder findOneByMetaData aufrufen. Aus diesem Grund sehen Sie mehrere Abfragen.

Ihre findOneByMetaData Funktion wie folgt aussehen sollte:

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

    $article->setMetaData($metadata); 

    return $article; 
} 

Lehre kümmern wird, ob der Artikel noch geladen ist, so gibt es keine Notwendigkeit für einen Nullwert, um zu versuchen und zu überprüfen. Gleiches gilt auch für Ihre findOneByArticle Funktion.

Hoffen Sie, dass dies sinnvoll ist, und hilft Ihnen, Ihr Problem zu lösen.

+0

Vielen Dank für Ihren Vorschlag. Ich glaube, Sie haben Recht, dass ein solcher Anruf falsch ist. In der Praxis macht das leider keinen Unterschied. Ich habe meinen Beitrag jedoch mit Ihren Verbesserungen aktualisiert. – Xatoo

1

Dies ist wegen Logger (LoggableCursor), dupliziert Abfragen in der Protokolldatei. Zum Beispiel, rufen Sie ... find() -> Limit (1) -> getQuery() es protokolliert jeden Aufruf, aber eigentlich gibt es eine einzige Abfrage Anfrage.

Weitere Informationen: https://github.com/doctrine/mongodb-odm/issues/471#issuecomment-63999514

ODM Ausgabe: https://github.com/doctrine/mongodb/issues/151

+0

Danke. Ich hatte dieses Problem vorher nicht gesehen. Aufgrund der oben genannten Probleme würden die zusätzlichen Abfragen nur protokolliert, aber nicht ausgeführt, richtig? Wenn ich jedoch MongoDB selbst anmelde, kann ich bestätigen, dass alle Abfragen tatsächlich an die Datenbank gesendet werden. – Xatoo

+0

Meinst du "Artikel finden" und "Artikel_meta finden" oder alle Abfragen im Protokoll? – ScorpioT1000

+0

Alle drei finden Abfragen. – Xatoo

Verwandte Themen