2015-01-08 9 views
8

Come si può usare Doctrine ODM per creare un riferimento bi-direzionale one-to-one che carichi pigri mentre si utilizza un campo diverso da quello principale per il riferimento?Doctrine ODM OneToOne Riferimento bidirezionale utilizzando repositoryMethod

Ho due raccolte in MongoDB con documenti, articolo e articoloMetaData. Per ogni documento di articolo, c'è un ArticleMetaData e viceversa. (Una relazione bidirezionale OneToOne.) Per motivi ereditari, i due tipi di documento devono essere in raccolte separate. Entrambe le collezioni sono aggiornate da sistemi esterni che non hanno alcuna conoscenza degli ID Mongo. Tuttavia contengono un "codice di gruppo" di campo condiviso che può essere utilizzato per abbinare l'articolo giusto ai suoi metadati.

Provo a configurare Doctrine in modo tale da ottenere i metadati per un oggetto articolo e un articolo dal suo oggetto metadati, ma voglio mantenerli pigri. (Non c'è bisogno di interrogare per l'altra estremità quando io non ne ho bisogno.)

Le mappature apparire come segue:

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 

E i metodi di repository di cui sopra:

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

Tutto sembra funzionare abbastanza bene. Posso interrogare un Articolo o ArticoloMetaData e ottenere l'altro lato, solo il il problema è: non sembra il carico pigro. Quando ho query per un articolo:

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

Un sacco di domande vengono eseguite:

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

Che cosa sto facendo di sbagliato? C'è un modo per portare a termine un riferimento bidirezionale bidirezionale con i vincoli precedenti?

Edit:

Dopo aver letto la risposta di Rob Holmes' ho tolto un test nei metodi repository che potrebbero aver causato il problema. Sfortunatamente il problema rimane e ci sono ancora 3 query in esecuzione dove uno (o due al massimo) è sufficiente.

risposta

1

Doctrine ODM caricherà già il documento di riferimento, invece di eseguirne il precaricamento.

Credo che il problema risiede in realtà nei tuoi metodi repository ... Per esempio, nella funzione findOneByMetaData la prima cosa che si sta facendo sta chiamando $metadata->getArticle() nel fare questo si sta chiedendo la dottrina di caricare l'articolo dal database, che a causa al tuo repositoryMethod chiamerà di nuovo findOneByMetaData. Questo è il motivo per cui visualizzi più query.

La vostra funzione findOneByMetaData dovrebbe apparire più simile a questo:

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

    $article->setMetaData($metadata); 

    return $article; 
} 

Dottrina si prenderà cura di se l'articolo è stato ancora caricato, quindi non c'è bisogno di cercare di verificare la presenza di un valore nullo. Lo stesso vale anche per la tua funzione findOneByArticle.

Spero che questo abbia un senso e ti aiuti a risolvere il tuo problema.

+0

Grazie per il suggerimento. Credo che tu abbia ragione nel dire che una tale chiamata è sbagliata. Sfortunatamente, in pratica, non fa alcuna differenza. Ho comunque aggiornato il mio post con i tuoi miglioramenti. – Xatoo

1

Questo a causa di Logger (logger di registro), duplica le query nel file di registro. Ad esempio, si chiama ... find() -> limit (1) -> getQuery() registra ogni chiamata ma in realtà vi è una singola richiesta di query.

Maggiori informazioni: numero https://github.com/doctrine/mongodb-odm/issues/471#issuecomment-63999514

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

+0

Grazie. Non avevo mai visto questo problema prima. In base ai problemi sopra menzionati, le query aggiuntive verrebbero registrate ma non effettivamente eseguite, giusto? Tuttavia, quando accendo il log in MongoDB, posso confermare che tutte le query sono effettivamente inviate al database. – Xatoo

+0

Vuoi dire "trova articolo" e "trova article_meta" o tutte le query nel registro? – ScorpioT1000

+0

Tutte e tre trovano le query. – Xatoo