MongoDB引用的文档与Doctrine ODM之间的延迟加载 [英] Lazy load between referenced documents on MongoDB with Doctrine ODM

查看:160
本文介绍了MongoDB引用的文档与Doctrine ODM之间的延迟加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Helo,



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



我正在迁移数据容器的一个Symfony2应用程序到MongoDB之前,它运行与MySQL。



我添加了DoctrineMongoDBBundle和几乎所有的东西完美的工作。
$ b

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





和一些例子说明如何创建关系并定义文档以获得懒惰负载行为,





但是我不能让它工作。



在我的情况下,我有两个文件旅行和笔记与一个1:N的关系,我想保持,这样的东西:

 <?php 

命名空间MyApp\TravelBundle\Document;

使用Doctrine\ODM\MongoDB\Mapping\Annotations作为ODM;
使用Doctrine\Common\Collections\ArrayCollection;
使用Symfony\Component\Validator\Constraints作为Assert;
使用Gedmo\Mapping\Annotation作为Gedmo;

/ **
*旅行
*
* @ ODM\Document(collection =travel)
* /
class旅行{

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

//更多属性...

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

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

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

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

//更多方法...

}
?>

<?php

命名空间MyApp\NoteBundle\Document;

使用Doctrine\ODM\MongoDB\Mapping\Annotations作为ODM;
使用Symfony\Component\Validator\Constraints作为Assert;
使用Gedmo\Mapping\Annotation作为Gedmo;

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

//更多属性...

/ **
*设置旅行
*
* @param \MyApp\ TravelBundle\Document\Travel $ travel
* @return注
* /
公共功能setTravel(\MyApp\TravelBundle\Document\Travel $ travel){
$ this-> travel = $ travel;
$ travel-> addNote($ this);

return $ this;
}

//更多方法...

}
?>

当我向旅行添加记录时,我了解旅行证件的结果应该是: / p>

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

,笔记文件应为:

  { _id:ObjectId(5183aa63095a1a3955000000),
travel:{$ ref:travel,
$ id:ObjectId(5183aa63095a1a3921000000),

note:First note,
createdAt:日期(1367583331000),
updatedAt:日期(1367583331000)}

但是现在我只在笔记文件中获得参考,而tra中没有引用vel文件,当我在旅行证件Doctrine中查询时,请勿加载相关的笔记文件:

 <?php 


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


?>

我在追加旅行注意事项的过程如下:

 <?php 

命名空间MyApp\TravelBundle\Controller;

使用Symfony\Bundle\FrameworkBundle\Controller\Controller;
使用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);
如果($ form-> isValid()){
$ entity-> setTravel($ travel);
$ dm> persist($ travel);
$ dm> persist($ entity);
$ dm> flush();
}
}
}
}
?>

获取方法$ travel-> getNotes()的任何想法或建议可以通过懒惰的负载。



非常感谢您的贡献,



Zacarías

解决方案

你想要实现的是简单地删除 mappedBy code> Reference $ <$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ @ ODM\ReferenceMany(targetDocument =\MyApp\NoteBundle\Document\Note,sort = {createdAt=asc})

以这种方式,学说会将Notes ID存储在 $ nodes 数组中。 p>




替换为mappedBy,Doctrine 不将Notes的 code> $ notes 数组,而是会执行这样的查询来获取实际的笔记:

 code> db.Notes.f ind({travel。$ id:< travelId>}); 

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



还要注意,使用 ReferenceMany 使用 mappedBy 是懒惰的:只有当您尝试循环 $ notes 数组时,它将实际执行查询,所以它也是轻量级的。



请参阅 doc 了解更多信息。


Helo,

firstly, please excuse my English, is not very good.

I am migrating the data container of a Symfony2 application to MongoDB, before that it run with MySQL.

I added the DoctrineMongoDBBundle and "almost everything" works perfectly.

I have some references between documents in which I would like to keep the "lazy load" pattern offered by the Doctrine ORM. I have read the official documentation for Doctrine ODM,

and some examples that explain how to create relations and define documents to get "lazy load" behavior,

but I can not make it work.

In my case, I have two documents, "travel" and "note" with a 1:N relationship I want to keep, something like this:

<?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 ...

}
?>

When I add a note to a travel I understand that the result for the travel document should be:

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

and for the note document should be:

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

but for now I only get a reference in the note document, whilst no reference appears in the travel document, and when I do a query in the travel document Doctrine do not load the related note documents:

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

The process I follow to add a note to a travel is as follows:

<?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();
            }
        }
    }
}
?>

Any ideas or suggestions to get the method $travel->getNotes() can automatically retrieve referenced notes through the "lazy load".

Thank you very much beforehand for the contributions,

Zacarías

解决方案

What you want to achieve is done by simply removing the mappedBy attribute in the ReferenceOne of the $travel property:

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

In this way doctrine will store the Notes IDs in the $nodes array.


With "mappedBy" instead, Doctrine doesn't store the IDs of the Notes in the $notes array, but instead it will do a query like this to fetch the actual notes:

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

Note that IMHO this one is the preferred approach, since in this way when you add/remove a note, you don't have to update the Travel doc. (however you'll have to add an index on the $travel field)

Also notice that with ReferenceMany, using the mappedBy is lazy: only when you try to cycle the $notes array it will actually execute the query, so it is also lightweight.

See the doc for more info.

这篇关于MongoDB引用的文档与Doctrine ODM之间的延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆