简体   繁体   中英

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?

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM