发出持久嵌套嵌套的嵌入式文档

如何解决发出持久嵌套嵌套的嵌入式文档

| 更新:可以肯定,这是一个错误,在Jira上引起了问题:http://bit.ly/gpstW9 更新(2011年5月5日):根据jwage的建议,我已切换到“类别”和“帖子”之间的“引用关系”(与“嵌入”相对)。 我正在使用最新版本的Doctrine ODM(来自Git的最新版本)。 我有三个级别的文档(两个嵌入式);类别-> EmbedsMany:发布-> EmbedsMany PostVersion。 PostVersion由Post自动处理。当我发表新文章时,实际上也会在幕后制作新的PostVersion。 我的问题是,Doctrine与PostVersions混淆,如果我检索现有的Category并向其中添加新的Post,则新Post \的PostVersions会添加到Category的$ posts集合中的第一个Post中。 一步步: 新建一个帖子(Post1)和类别 将Post1添加到类别 持久性类别,冲洗,清除 检索类别 撰写新文章(Post2) 将Post2添加到类别 冲洗 在数据库的这一阶段,应该有一个类别,两个帖子,每个帖子都有一个PostVersion。但是,实际发生的是一个类别,两个帖子,第一个帖子具有两个PostVersions,第二个帖子具有零个PostVersions。 在请求期间,文档本身是正确的,只是要将其持久化到错误的数据库中。我想念什么? 预期结果:
{
  \"_id\": ObjectId(\"4da66baa6dd08df1f6000001\"),\"name\": \"The Category\",\"posts\": [
    {
      \"_id\": ObjectId(\"4da66baa6dd08df1f6000002\"),\"activeVersionIndex\": 0,\"versions\": [
        {
          \"_id\": ObjectId(\"4da66baa6dd08df1f6000003\"),\"name\": \"One Post\",\"content\": \"One Content\",\"metaDescription\": null,\"isAutosave\": false,\"createdAt\": \"Thu,14 Apr 2011 13:36:10 +1000\",\"createdBy\": \"Cobby\"
        }
      ]
    },{
      \"_id\": ObjectId(\"4da66baa6dd08df1f6000004\"),\"activeVersionIndex\": 0
      \"versions\": [
        {
          \"_id\": ObjectId(\"4da66baa6dd08df1f6000005\"),\"name\": \"Two Post\",\"content\": \"Two Content\",\"createdBy\": \"Cobby\"
        }
      ]
    }
  ]
}
实际结果:
{
  \"_id\": ObjectId(\"4da66baa6dd08df1f6000001\"),\"createdBy\": \"Cobby\"
        },{
          \"_id\": ObjectId(\"4da66baa6dd08df1f6000005\"),\"activeVersionIndex\": 0
    }
  ]
}
这是我的文件 Category.php
<?php

namespace Documents\\Blog;

use Doctrine\\Common\\Collections\\ArrayCollection;

/**
 * @Document(collection=\"blog\")
 * @HasLifecycleCallbacks
 */
class Category
{

    /**
     * @Id
     */
    private $id;

    /**
     * @String
     */
    private $name;

    /**
     * @EmbedMany(targetDocument=\"Documents\\Blog\\Post\")
     */
    private $posts;

    public function __construct($name = null)
    {
        $this->posts = new ArrayCollection();
        $this->setName($name);
    }

    public function getId()    
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getPosts()
    {
        return $this->posts->toArray();
    }

    public function addPost(Post $post)
    {
        $this->posts->add($post);
    }

    public function getPost($id)
    {
        return $this->posts->filter(function($post) use($id){
            return $post->getId() === $id;
        })->first();
    }

}
Post.php
<?php

namespace Documents\\Blog;

use Doctrine\\Common\\Collections\\ArrayCollection;

/**
 * @EmbeddedDocument
 * @HasLifecycleCallbacks
 */
class Post
{

    /**
     * @Id
     */
    private $id;

    private $firstVersion;

    private $activeVersion;

    /**
     * @Int
     */
    private $activeVersionIndex;

    /**
     * @EmbedMany(targetDocument=\"Documents\\Blog\\PostVersion\")
     */
    private $versions;

    static private $currentUser;

    private $isDirty = false;

    public function __construct($name = \"\",$content = \"\")
    {
        if(!self::$currentUser){
            throw new \\BlogException(\"Cannot create a post without the current user being set\");
        }

        $this->versions      = new ArrayCollection();
        $this->activeVersion = $this->firstVersion = new PostVersion($name,$content,self::$currentUser);
        $this->versions->add($this->firstVersion);
        $this->isDirty = true;
    }

    public function getId()     
    {
        return $this->id;
    }

    public function getFirstVersion()
    {
        return $this->firstVersion;
    }

    public function getActiveVersion()
    {
        return $this->activeVersion;
    }

    public function setName($name)
    {
        $this->_setVersionValue(\'name\',$name);
    }

    public function getName()
    {
        return $this->getActiveVersion()->getName();
    }

    public function setContent($content)
    {
        $this->_setVersionValue(\'content\',$content);
    }

    public function getContent()
    {
        return $this->getActiveVersion()->getContent();
    }

    public function setMetaDescription($metaDescription)
    {
        $this->_setVersionValue(\'metaDescription\',$metaDescription);
    }

    public function getMetaDescription()
    {
        return $this->getActiveVersion()->getMetaDescription();
    }

    public function getVersions()
    {
        return $this->versions->toArray();
    }

    private function _setVersionValue($property,$value)
    {   
        $version = $this->activeVersion;

        if(!$this->isDirty){
        // not dirty,make a new version
            $version = new PostVersion($version->getName(),$version->getContent(),self::getCurrentUser());
        }

        $refl = new \\ReflectionProperty(get_class($version),$property);
        $refl->setAccessible(true);

        // updated current user
        $refl->setValue($version,$value);

        // unset ID
        $refl = new \\ReflectionProperty(get_class($version),\'id\');
        $refl->setAccessible(true);
        $refl->setValue($version,null);

        // updated self
        if(!$this->isDirty){
            $this->activeVersion = $version;
            $this->versions->add($version);
            $this->isDirty = true;
        }

        // no first version,this must be the first
        if($this->versions->count() === 1){
            $this->firstVersion = $version;
        }
    }

    static public function setCurrentUser($user)
    {
        self::$currentUser = $user;
    }

    static public function getCurrentUser()
    {
        return self::$currentUser;
    }

    /**
     * @PostLoad
     */
    public function findFirstVersion()
    {
        $firstVersion = null;
        foreach($this->versions as $version){
            if(null === $firstVersion){
                // first iteration,start with any version
                $firstVersion = $version;
                continue;
            }

            if($version->getCreatedAt() < $firstVersion->getCreatedAt()){
                // current version is newer than existing version
                $firstVersion = $version;
            }
        }

        if(null === $firstVersion){
            throw new \\DomainException(\"No first version found.\");
        }

        $this->firstVersion = $firstVersion;
    }

    /**
     * @PostLoad
     */
    public function findActiveVersion()
    {
        $this->activeVersion = $this->versions->get($this->activeVersionIndex);
    }

    /**
     * @PrePersist
     * @PreUpdate
     */
    public function doActiveVersionIndex()
    {
        $this->activeVersionIndex = $this->versions->indexOf($this->activeVersion);
        $this->isDirty = false;
    }

    /**
     * @PostPersist
     * @PostUpdate
     */
    public function makeClean()
    {
        $this->isDirty = false;
    }

    public function getCreatedBy()
    {
        return $this->getFirstVersion()->getCreatedBy();
    }

    public function getCreatedAt()
    {
        return $this->getFirstVersion()->getCreatedAt();
    }

}
PostVersion.php
<?php

namespace Documents\\Blog;

/**
 * @EmbeddedDocument
 */
class PostVersion
{

    /**
     * @Id
     */
    private $id;

    /**
     * @String
     */
    private $name;

    /**
     * @String
     */
    private $content;

    /**
     * @String(nullable=\"true\")
     */
    private $metaDescription;

    /**
     * @Boolean
     */
    private $isAutosave = false;

    /**
     * @Date
     */
    private $createdAt;

    /**
     * @String
     */
    private $createdBy;

    public function __construct($name,$author)
    {
        $this->setName($name);
        $this->setContent($content);
        $this->setCreatedBy($author);
        $this->touch();
    }

    public function __clone()
    {
        if($this->id){
            $this->id = null;
            $this->touch();
        }
    }

    private function touch()
    {
        $this->createdAt = new \\DateTime();
    }

    public function getId()     
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getContent()
    {
        return $this->content;
    }

    public function setContent($content)
    {
        $this->content = $content;
    }

    public function getIsAutosave()
    {
        return $this->isAutosave;
    }

    public function setIsAutosave($isAutosave)
    {
        $this->isAutosave = $isAutosave;
    }

    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    public function setCreatedAt(\\DateTime $createdAt)
    {
        $this->createdAt = $createdAt;
    }

    public function getCreatedBy()
    {
        return $this->createdBy;
    }

    public function setCreatedBy($createdBy)
    {
        $this->createdBy = $createdBy;
    }

    public function setMetaDescription($metaDescription)
    {
        $this->metaDescription = $metaDescription;
    }

    public function getMetaDescription()
    {
        return $this->metaDescription;
    }

}
...我该去xdebug了。     

解决方法

现在,我已经通过创建一个EventSubscriber来解决此问题,该事件会延迟持久化嵌套的嵌入式文档,如下所示:
<?php

namespace Application\\Blog\\Domain\\EventSubscribers;

use Application\\Blog\\Domain\\Document\\Post,Doctrine\\ODM\\MongoDB\\Event\\LifecycleEventArgs,Doctrine\\ODM\\MongoDB\\Mapping\\ClassMetadata;

/**
 * Handles delayed insert of nested embedded documents to work around Doctrine ODM bug :(
 */
class VersionManager implements \\Doctrine\\Common\\EventSubscriber
{

    private $versions = array();

    /**
     * Returns an array of events this subscriber wants to listen to.
     *
     * @return array
     */
    public function getSubscribedEvents()
    {
        return array(\'prePersist\',\'postPersist\');
    }

    /**
     * Move versions out of Posts into temporary storage so they are flushed without versions
     *
     * @param \\Doctrine\\ODM\\MongoDB\\Event\\LifecycleEventArgs $eventArgs
     * @return void
     */
    public function prePersist(LifecycleEventArgs $eventArgs)
    {
        $document = $eventArgs->getDocument();
        if($document instanceof Post){
            $dm = $eventArgs->getDocumentManager();
            $meta = $dm->getClassMetadata(get_class($document));
            $this->addVersion($meta,$document);
            $this->clearVersions($meta,$document);
        }
    }

    /**
     * Move the temporary versions back onto the Posts and flush
     *
     * @param \\Doctrine\\ODM\\MongoDB\\Event\\LifecycleEventArgs $eventArgs
     * @return void
     */
    public function postPersist(LifecycleEventArgs $eventArgs)
    {
        $dm = $eventArgs->getDocumentManager();
        $hasChanges = count($this->versions) > 0;

        foreach($this->versions as $oid => $value){
            $post = $value[\'document\'];
            $versions = $value[\'versions\'];
            $meta = $dm->getClassMetadata(get_class($post));
            $meta->setFieldValue($post,\'versions\',$versions);
            unset($this->versions[$oid]);
        }

        if($hasChanges){
            $dm->flush();
        }
    }

    /**
     * Add versions to temporary storage
     *
     * @param \\Doctrine\\ODM\\MongoDB\\Mapping\\ClassMetadata $meta
     * @param \\Application\\Blog\\Domain\\Document\\Post $post
     * @return void
     */
    private function addVersion(ClassMetadata $meta,Post $post)
    {
        $this->versions[spl_object_hash($post)] = array(
            \'document\' => $post,\'versions\' => $meta->getFieldValue($post,\'versions\')
        );
    }

    /**
     * Remove versions from a Post
     *
     * @param \\Doctrine\\ODM\\MongoDB\\Mapping\\ClassMetadata $meta
     * @param \\Application\\Blog\\Domain\\Document\\Post $post
     * @return void
     */
    private function clearVersions(ClassMetadata $meta,Post $post)
    {
        $meta->setFieldValue($post,null);
    }

}
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-