[英]Doctrine ODM OneToOne Bi-Directional Reference using repositoryMethod
在使用主键以外的字段进行引用时,如何使用Doctrine ODM创建一对一的双向引用,从而延迟加载?
我在MongoDB中有两个带有文档的集合,即Article和ArticleMetaData。 对于每个Article文档,都有一个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
以及上面提到的存储库方法:
// 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":[]}
我究竟做错了什么? 有什么办法可以完成具有上述约束的延迟加载一对一双向引用?
编辑:
阅读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;
}
Doctrine会检查文章是否已加载,因此无需尝试检查空值。 这同样也适用于您的findOneByArticle
函数。
希望这有道理,并可以帮助您解决问题。
这是因为有Logger(loggableCursor),它会在日志文件中重复查询。 例如,您调用... find()-> limit(1)-> getQuery()会记录每个调用,但实际上只有一个查询请求。
更多信息: https : //github.com/doctrine/mongodb-odm/issues/471#issuecomment-63999514
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.