使用repositoryMethod的Doctrine ODM OneToOne双向引用

时间:2015-01-08 14:33:00

标签: 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

上面提到的存储库方法:

// 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个查询正在执行,其中一个(或最多两个)就足够了。

2 个答案:

答案 0 :(得分:1)

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功能。

希望这有意义,并帮助您解决问题。

答案 1 :(得分: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