Xat*_*too 8 php mongodb symfony doctrine-orm doctrine-odm
如何使用Doctrine ODM创建一对一的双向引用,在使用除主键之外的字段进行引用时延迟加载?
我在MongoDB中有两个文档,Article和ArticleMetaData.对于每个文章文档,都有一个ArticleMetaData,反之亦然.(OneToOne双向关系.)由于遗留原因,这两种文档类型需要位于不同的集合中.两个集合都由不了解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
Run Code Online (Sandbox Code Playgroud)
以及上面提到的存储库方法:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
这一切似乎都很有效.我可以查询Article或ArticleMetaData并获取另一方,只有问题是:它似乎没有延迟加载.当我查询文章时:
$article = $documentManager
->getRepository('FooBarBundle:Article')
->findOneBy(['groupcode' => 123]);
Run Code Online (Sandbox Code Playgroud)
执行了很多查询:
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":[]}
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?有没有办法可以完成具有上述约束的延迟加载一对一双向参考?
编辑:
阅读Rob Holmes的回答后,我删除了可能导致问题的存储库方法中的测试.不幸的是,问题仍然存在,并且仍有3个查询正在执行,其中一个(或最多两个)就足够了.
Doctrine ODM 已经延迟加载引用的文档,而不是为您预取它。
我相信你的问题实际上在于你的存储库方法......例如,在函数中,findOneByMetaData你要做的第一件事是调用$metadata->getArticle()这样做,你要求学说从数据库加载文章,由于你的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;
}
Run Code Online (Sandbox Code Playgroud)
Doctrine 将处理文章是否已加载,因此无需尝试检查空值。这同样也适用于你的findOneByArticle函数。
希望这是有道理的,并帮助您解决问题。