当与实体管理器多次合并时,Symfony/Doctrine实体会导致脏实体关联

har*_*mon 9 serialization symfony doctrine-orm

我正在使用Symfony2和Doctrine

我有一个doctrine实体,它被序列化/反序列化为一个会话并用于多个屏幕.该实体具有多个一对多关联.

该学说实体具有以下一对多,例如:

class Article {

...

    /**
     * @ORM\OneToMany(targetEntity="image", mappedBy="article", cascade=  {"merge","detach","persist"})
     */
    protected $images;

    public function __construct()
    {
        $this->images = new ArrayCollection();
    }

    .....
}
Run Code Online (Sandbox Code Playgroud)

文章实体按如下方式保存和检索:

    public function saveArticle($article)
    {
        $articleSerialized = serialize($article);
        $this->session->set('currentArticle',$articleSerialized);
    }

    public function getArticle()
    {
        $articleSerialized = $this->session->get('currentArticle');
        $article = unserialize($articleSerialized);
        $article = $this->em->merge($article);

        return $article;
    }
Run Code Online (Sandbox Code Playgroud)

我可以多次向会话中保存和加载实体,然后将其合并回实体管理器并保存.这只是它是一个新实体.

但是,一旦我从数据库加载实体然后将其保存到会话,我就会遇到问题.

我知道,从其他帖子中,在您取消序列化已保存的实体后,您必须运行$ em-> merge($ entity);

我能够合并实体,添加一个新的子实体(一对多),然后保存:

$article = $this->getArticle(); //Declared above, gets article from session

$image = new Image();
$image->setFilename('image.jpeg');
$article->addImage($image);

$this->saveArticle($article); //Declared above, returns the article to session
Run Code Online (Sandbox Code Playgroud)

但是,在第一次合并和图像添加后,我无法再添加任何子实体.如果我尝试添加第二个图像,它会返回以下错误:

A managed+dirty entity <<namespace of entity>>
image@0000000067078d7400000000221d7e02 can not 
be scheduled for insertion.
Run Code Online (Sandbox Code Playgroud)

总而言之,我可以对实体进行任意数量的更改并将其保存到会话中,但如果我在添加子实体时多次运行$ em-> merge,则新的子实体将标记为脏.

有人知道为什么一个实体会被标记为脏吗?我是否需要重置实体本身,如果是,我该怎么做?

har*_*mon 11

得到它了.

对于任何可能在将来遇到此问题的人:

您无法合并具有未加载子实体的实体.它们被标记为脏.

IE

您可能有一篇文章,其中两张图片已保存到DB.

ARTICLE (ID 1) -> IMAGE (ID 1)
               -> IMAGE (ID 2)
Run Code Online (Sandbox Code Playgroud)

如果将文章序列化保存到会话,然后反序列化并合并它.没关系.

如果添加新图像,然后将其序列化为会话,则会出现问题.这是因为您无法合并未加载的实体.

ARTICLE (ID 1) -> IMAGE (ID 1)
               -> IMAGE (ID 2)
               -> IMAGE (NOT YET PERSISTED)
Run Code Online (Sandbox Code Playgroud)

我必须做的是:

在我反序列化文章后,我删除了未经存在的图像并将它们存储在一个临时数组中(我检查ID).然后我合并了文章并重新添加了未经加载的图像.

        $article = unserialize($this->session->get('currentArticle'));

        $tempImageList = array();

        foreach($article->getImages() as $image)
        {
            if(!$image->getId()) //If image is new, move it to a temporary array
            {
                $tempImageList[] = $image;
                $article->removeImage($image);
            }
        }

        $plug = $this->em->merge($article); //It is now safe to merge the entity

        foreach($tempImageList as $image)
        {
            $article->addImage($image); //Add the image back into the newly merged plug
        }

        return $article;                        
Run Code Online (Sandbox Code Playgroud)

然后,如果需要,我可以添加更多图像,并重复该过程,直到我最终将文章保留回DB.

如果您需要执行多页创建过程或通过AJAX添加图像,这很方便.