Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony/Doctrine entity leads to dirty entity association when merged multiple times with entity manager

I am using Symfony2 and Doctrine

I have a doctrine entity which is serialized/unserialized to a session and used in multiple screens. This entity has a number of one to many associations.

The doctrine entity has the following one to many, for example:

class Article {

...

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

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

    .....
}

The article entity is saved and retrieved as follows:

    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;
    }

I am able to save and load the entity to and from the session any number of times, and then merge it back to the entity manager and save. This is only if it is a new entity.

However, once I load an entity from the db and then save it to session, I get problems.

I know, from other posts, that after you unserialise a saved entity, you have to run $em->merge($entity);

I am able to merge the entity, add a new sub-entity (one to many) and then save:

$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

However, after the first merge and image add, I can't add any more sub-entities. If i try to add a second image, It returns the following error:

A managed+dirty entity <<namespace of entity>>
image@0000000067078d7400000000221d7e02 can not 
be scheduled for insertion.

So in summary, i can make any number of changes to an entity and save it to session, but if I run $em->merge more than once while adding sub-entities, the new sub-entities are marked as dirty.

Does anybody know why an entity would be marked as dirty? Do I need to reset the entity itself, and if so, how could I do that?

like image 572
harraksimon Avatar asked Dec 05 '12 00:12

harraksimon


1 Answers

Got it.

For anyone who might run into this problem in the future:

You cannot merge an entity which has unpersisted sub-entities. They become marked as dirty.

I.E

You may have an article with two images already saved to DB.

ARTICLE (ID 1) -> IMAGE (ID 1)
               -> IMAGE (ID 2)

If you save serialise the article to session and then unserialize and merge it. It's ok.

If you add a new image, then serialize it to session you will have problems. This is because you cannot merge an unpersisted entity.

ARTICLE (ID 1) -> IMAGE (ID 1)
               -> IMAGE (ID 2)
               -> IMAGE (NOT YET PERSISTED)

What I had to do was:

After I unserialize the article, I remove the unpersisted images and store them in a temporary array (I check for ID). THEN i merge the article and re-add the unpersisted image(s).

        $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;                        

I can then add more images if need be, and repeat the process until I finally persist the article back to DB.

This is handy to know in the event you need to do a multiple pages creation process or adding images via AJAX.

like image 122
harraksimon Avatar answered Oct 08 '22 03:10

harraksimon