Doctrine ODM OneToOne Двунаправленная ссылка с использованием репозиторияMethod

Как можно использовать Doctrine ODM для создания двунаправленной ссылки «один-к-одному», которая лениво загружается при использовании для ссылки поля, отличного от первичного ключа?

У меня есть две коллекции в MongoDB с документами Article и ArticleMetaData. Для каждого документа Article есть ArticleMetaData и наоборот. (Двунаправленное отношение OneToOne.) По унаследованным причинам два типа документов должны находиться в отдельных коллекциях. Обе коллекции обновляются внешними системами, которые не знают идентификаторов Mongo. Однако они содержат общее поле «групповой код», которое можно использовать для сопоставления нужной статьи с ее метаданными.

Я пытаюсь настроить 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":[]}

Что я делаю неправильно? Есть ли способ, которым я могу выполнить двунаправленную ссылку «один на один» с отложенной загрузкой, имеющую вышеуказанные ограничения?

Редактировать:

Прочитав ответ Роба Холмса, я удалил тест методов репозитория, который мог вызвать проблему. К сожалению, проблема все еще остается, и до сих пор выполняется 3 запроса, где достаточно одного (или не более двух).

8

Решение

Doctrine ODM уже будет лениво загружать ссылочный документ, а не предварительно выбирать его для вас.

Я считаю, что ваша проблема на самом деле заключается в ваших методах хранилища … Например, в findOneByMetaData функционировать первое, что вы делаете, звонит $metadata->getArticle() при этом вы просите доктрину загрузить статью из базы данных, которую из-за вашего хранилища будет вызывать метод 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;
}

Doctrine позаботится о том, была ли статья загружена, поэтому нет необходимости пытаться проверить нулевое значение. То же самое относится и к вашему findOneByArticle функция тоже.

Надеюсь, что это имеет смысл, и поможет вам решить вашу проблему.

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

1

По вопросам рекламы [email protected]