Emptying collection containing Single-Inheritence Discriminated Entity uses a dangerous DELETE statements that can lead to unintentionally removed records for different entities within the same single table inheritance.
Current behavior
When an Entity UserA has a property things which is a OneToMany relation with orphanRemoval enabled to an Entity ThingA (references UserA via a property of owner) which is part of a single table hierarchy (using discriminator mapping) extending from AbstractThing, doing the following:
$userA->getThings()->clear();
and persisting+flushing causes the db to receive iterated DELETE statements for the records in the Collection (e.g. DELETE FROM things WHERE id = 1; DELETE FROM things WHERE id = 2; #... etc.)
If instead you do:
class UserA {
public function setThings(ArrayCollection $things): void
{
$this->things = $things;
}
...
}
...
$userA->setThings(new ArrayCollection());
and persist+flush, then the database instead receives a request of the form DELETE FROM things WHERE owner_id = 1;, without the discriminator column in the WHERE clause.
This can cause a problem in the instance where another Entity in the same hierarchy, ThingB, has an association to a different entity, UserB, using the same property name since this could lead to collisions in the UserA/UserB owned records leading to entities from one being removed due to the deletion of those associated with the other.
I would expect the delete directive to include the discriminator column in addition to the id. Or, if $userA->setThings(new ArrayCollection()); is improper, it should be guarded against.
Bug Report
Summary
Emptying collection containing Single-Inheritence Discriminated Entity uses a dangerous DELETE statements that can lead to unintentionally removed records for different entities within the same single table inheritance.
Current behavior
When an Entity
UserA
has a propertythings
which is a OneToMany relation with orphanRemoval enabled to an EntityThingA
(referencesUserA
via a property ofowner
) which is part of a single table hierarchy (using discriminator mapping) extending fromAbstractThing
, doing the following:$userA->getThings()->clear();
and persisting+flushing causes the db to receive iterated DELETE statements for the records in the Collection (e.g.
DELETE FROM things WHERE id = 1; DELETE FROM things WHERE id = 2; #... etc.
)If instead you do:
and persist+flush, then the database instead receives a request of the form
DELETE FROM things WHERE owner_id = 1;
, without the discriminator column in the WHERE clause.This can cause a problem in the instance where another Entity in the same hierarchy,
ThingB
, has an association to a different entity,UserB
, using the same property name since this could lead to collisions in theUserA
/UserB
owned records leading to entities from one being removed due to the deletion of those associated with the other.How to reproduce
Minimal reproducible example: https://github.com/gitbugr/doctrine-assoc-delete-example
Expected behavior
I would expect the delete directive to include the discriminator column in addition to the id. Or, if
$userA->setThings(new ArrayCollection());
is improper, it should be guarded against.