繁体   English   中英

使用Doctrine ODM在MongoDB上引用文档之间的延迟加载

[英]Lazy load between referenced documents on MongoDB with Doctrine ODM

直升机,

首先,请原谅我的英语,不是很好。

我正在将Symfony2应用程序的数据容器迁移到MongoDB,然后再运行MySQL。

我添加了DoctrineMongoDBBundle,“几乎所有东西”都完美无缺。

我在文档之间有一些参考,我希望保留Doctrine ORM提供的“延迟加载”模式。 我已经阅读了Doctrine ODM的官方文档,

以及一些解释如何创建关系和定义文档以获得“延迟加载”行为的示例,

但我不能让它发挥作用。

在我的情况下,我有两个文件,“旅行”和“注意”与我想要保持的1:N关系,如下所示:

<?php

namespace MyApp\TravelBundle\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;

/**
 * Travel
 *
 * @ODM\Document(collection="travel")
 */
class Travel {

    /**
     * @var \MyApp\NoteBundle\Document\Note
     * 
     * @ODM\ReferenceMany(targetDocument="\MyApp\NoteBundle\Document\Note", mappedBy="travel", sort={"createdAt"="asc"} )
     */
    private $notes;

    // more properties ...

    public function __construct() {
        $this->notes = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add notes
     *
     * @param \MyApp\NoteBundle\Document\Note $notes
     */
    public function addNote(\MyApp\NoteBundle\Document\Note $notes) {
        $this->notes[] = $notes;
    }

    /**
     * Remove notes
     *
     * @param \MyApp\NoteBundle\Document\Note $notes
     */
    public function removeNote(\MyApp\NoteBundle\Document\Note $notes) {
        $this->notes->removeElement($notes);
    }

    /**
     * Get notes
     *
     * @return Doctrine\Common\Collections\Collection $notes
     */
    public function getNotes() {
        return $this->notes;
    }

    // more methods ...

}
?>

<?php

namespace MyApp\NoteBundle\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;

/**
 * Note
 *
 * @ODM\Document(collection="note")
 */
class Note
{
    /**
     * @var \MyApp\TravelBundle\Document\Travel
     * 
     * @ODM\ReferenceOne(targetDocument="MyApp\TravelBundle\Document\Travel", inversedBy="notes")
     */
    private $travel;

    // more properties ...

    /**
     * Set travel
     *
     * @param \MyApp\TravelBundle\Document\Travel $travel
     * @return Note
     */
    public function setTravel(\MyApp\TravelBundle\Document\Travel $travel) {
        $this->travel = $travel;
        $travel->addNote($this);

        return $this;
    }

    // more methods ...

}
?>

当我在旅行中添加注释时,我理解旅行证件的结果应该是:

{ "_id" : ObjectId( "5183aa63095a1a3921000000" ),
  "name" : "First travel",
  "isActive" : true,
  "createdAt" : Date( 1367583331000 ),
  "updatedAt" : Date( 1367583331000 ),
  "notes" : [{ "$ref" : "note",
    "$id" : ObjectId( "5183aa63095a1a3955000000" ),
    "$db" : "mydb" }]
 }

而对于票据文件应该是:

{ "_id" : ObjectId( "5183aa63095a1a3955000000" ),
  "travel" : { "$ref" : "travel",
    "$id" : ObjectId( "5183aa63095a1a3921000000" ),
    "$db" : "mydb" },
  "note" : "First note",
  "createdAt" : Date( 1367583331000 ),
  "updatedAt" : Date( 1367583331000 ) }

但是现在我只在注释文档中得到一个引用,而旅行文档中没有引用,当我在旅行文档中查询时,Doctrine不会加载相关的注释文档:

<?php
.
.
$travel = $dm->getRepository('TravelBundle:Travel')->findCurrentTravel($user->getId());
$travel->getNotes(); // IS EMPTY :(
.
.
?>

我在旅行中添加注释的过程如下:

<?php

namespace MyApp\TravelBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class TravelController extends Controller {

    public function createNoteAction(Request $request) {
        $dm = $this->get('doctrine.odm.mongodb.document_manager');
        $travel = $dm->getRepository('TravelBundle:Travel')->findCurrentTravel($user->getId());
        $entity = new Note();
        $form = $this->createForm(newNoteType(), $entity);
        if ($request->isMethod('POST')) {
            $form->bind($request);
            if ($form->isValid()) {
                $entity->setTravel($travel);
                $dm>persist($travel);
                $dm>persist($entity);
                $dm>flush();
            }
        }
    }
}
?>

获取方法$ travel-> getNotes()的任何想法或建议都可以通过“延迟加载”自动检索引用的注释。

非常感谢您的贡献,

扎卡里亚斯

您想要实现的只需删除$travel属性的ReferenceOne中的mappedBy属性即可:

@ODM\ReferenceMany(targetDocument="\MyApp\NoteBundle\Document\Note", sort={"createdAt"="asc"} )

这样,doctrine会将Notes标识存储在$nodes数组中。


使用“mappedBy”代替,Doctrine 不会将Notes 的ID存储$notes数组中,而是会执行这样的查询来获取实际的注释:

db.Notes.find({travel.$id: <travelId>});

请注意,恕我直言这个是首选方法 ,因为这样当您添加/删除注释时,您不必更新Travel文档。 (但是你必须在$ travel字段上添加一个索引)

另请注意,使用ReferenceMany ,使用mappedBy是惰性的:只有当您尝试循环$notes数组时,它才会实际执行查询,因此它也是轻量级的。

有关详细信息,请参阅doc

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM