2015-01-08 9 views
8

W jaki sposób Doctrine ODM może być użyty do utworzenia dwukierunkowego odniesienia typu "jeden do jednego", który leniwy ładuje się przy użyciu pola innego niż klucz podstawowy dla odniesienia?Doctrine ODM OneToOne Bi-Directional Reference using repositoryMethod

Mam dwie kolekcje w MongoDB z dokumentami, artykułem i artykułemMetaData. Dla każdego dokumentu artykułu istnieje artykułMetaData i vice versa. (Dwukierunkowa relacja OneToOne). Ze względu na starsze wersje dwa typy dokumentów muszą znajdować się w osobnych kolekcjach. Obie kolekcje są aktualizowane przez systemy zewnętrzne, które nie mają wiedzy na temat identyfikatorów Mongo. Zawierają jednak wspólne pole "groupcode", które można wykorzystać do dopasowania właściwego artykułu do jego metadanych.

Próbuję skonfigurować Doctrine w taki sposób, aby uzyskać metadane dla obiektu artykułu i artykułu z jego obiektu meta-danych, ale chcę je zachować leniwy załadowany. (Nie ma potrzeby, aby zapytać o drugim końcu, kiedy nie jest to potrzebne).

mapowania wyglądać następująco:

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 

i metod repozytorium wspomniano powyżej:

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

Wszystko wydaje się działać całkiem dobrze. Mogę zapytać o artykuł lub artykułMetaData i dostać drugą stronę, tylko problemem jest: nie wydaje się leniwy załadować. Kiedy zapytać o artykuł:

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

Wiele zapytań są wykonywane:

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

Co robię źle? Czy istnieje sposób, w jaki mogę osiągnąć leniwy ładowanie dwukierunkowego odniesienia jeden do jednego z powyższymi ograniczeniami?

Edit:

Po przeczytaniu odpowiedź Roba Holmesa usunąłem test w repozytorium metod, które mogą być przyczyną problemu. Niestety, problem nadal istnieje i wciąż są wykonywane 3 kwerendy, w których jedna (lub co najwyżej dwie) wystarcza.

Odpowiedz

1

Doctrine ODM będzie już leniwym ładowaniem przywołanego dokumentu, zamiast wstępnie go pobrać.

Wierzę problem faktycznie leży w repozytorium metod ... Na przykład, w funkcji findOneByMetaData pierwszą rzeczą, którą robią dzwoniącej $metadata->getArticle() w ten sposób prosicie doktrynę, aby załadować artykuł z bazy danych, które ze względu do twojego repozytoriumMethod ponownie nazwie findOneByMetaData. Właśnie dlatego widzisz wiele zapytań.

Twoja funkcja findOneByMetaData powinien wyglądać mniej więcej tak:

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

    $article->setMetaData($metadata); 

    return $article; 
} 

Doktryna zajmie czy artykuł został jeszcze załadowany, więc nie ma potrzeby, aby spróbować i sprawdzić wartość null. To samo dotyczy również twojej funkcji findOneByArticle.

Mam nadzieję, że to ma sens i pomoże rozwiązać problem.

+0

Dziękuję za sugestię. Uważam, że masz rację, że takie wezwanie jest złe. Niestety w praktyce nie robi to żadnej różnicy. Mimo to zaktualizowałem swój post, wprowadzając usprawnienia. – Xatoo

1

Dzieje się tak z powodu Logger (loggableCursor), duplikuje zapytania w pliku dziennika. Na przykład, wywołujesz ... find() -> limit (1) -> getQuery() loguje każde wywołanie, ale faktycznie istnieje jedno zapytanie zapytania.

Więcej informacji: problem https://github.com/doctrine/mongodb-odm/issues/471#issuecomment-63999514

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

+0

Dziękuję. Nie widziałem wcześniej takich problemów. W oparciu o wyżej wymienione problemy dodatkowe zapytania byłyby rejestrowane, ale nie były uruchamiane, prawda? Jednak po włączeniu logowania w MongoDB mogę potwierdzić, że wszystkie zapytania są faktycznie wysyłane do bazy danych. – Xatoo

+0

Masz na myśli "znajdź artykuł" i "znajdź artykuł_meta" lub wszystkie zapytania w logu? – ScorpioT1000

+0

Wszystkie trzy wyszukiwane hasła. – Xatoo