Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine 2 Entities Relations Remove

I have an owning entity that has the following relation to an "attribute" entity:

/**
* @ORM\OneToMany(targetEntity="Attribute", mappedBy="entity", cascade={"persist", "remove", "merge"})
**/
protected $attributes;

On the side, the owned entity relation looks like this:

/**
* @ORM\ManyToOne(targetEntity="Entity", inversedBy="attributes")
* @ORM\JoinColumn(name="entity_id", referencedColumnName="id")
*/
protected $entity;

When I create an instance of an entity, add attributes to it and save it. It all works fine. When I remove one attribute from the entity and persist, the attribute is not deleted in the database and re-appears upon refresh.

Anyone has an idea?

like image 834
Nicholas Charbonneau Avatar asked May 15 '13 21:05

Nicholas Charbonneau


2 Answers

Solution

What you're looking for is orphan removal.

You can read on if you'd like details on why your current situation isn't working.

Cascade woes

The cascade operation won't do what you want unfortunately. The "cascade=[remove]" just means that if the entity object is removed then doctrine will loop through and remove all child attributes as well:

$em->remove($entity);
// doctrine will basically do the following automatically
foreach ($entity->getAttributes() as $attr)
{
    $em->remove($attr);
}

How to do it manually

If you needed to remove an attribute from an entity you'd delete the attribute like so:

$entity->getAttributes()->removeElement($attr);
$em->remove($attribute);

Solution details

But, to do that automatically we use the orphan removal option. We simply tell doctrine that attributes can only belong to entities, and if an attribute no longer belongs to an entity, simply delete it:

/**
 * @ORM\OneToMany(targetEntity="Attribute", mappedBy="entity", orphanRemoval=true, cascade={"persist", "remove", "merge"})
 **/
protected $attributes;

Then, you can remove the attribute by simply doing this:

$entity->getAttributes()->removeElement($attr);
like image 163
radnan Avatar answered Nov 15 '22 04:11

radnan


Be careful when using orphan removal.

If you remove an element and then call refresh on the main entity the element is not removed from the internal orphan removal array of doctrine.

And if flush is called later, will result in removing that entry from the db, ignoring the refresh.

This looks like a bug to me, and resulted in loss of images on a lot of products in my app. I had to implement a listener to call persist again on those entities, after they ware scheduled for delete.

like image 20
Alexandru Cosoi Avatar answered Nov 15 '22 03:11

Alexandru Cosoi