diff --git a/src/Persisters/Collection/OneToManyPersister.php b/src/Persisters/Collection/OneToManyPersister.php index f39415fc0c9..04fc5864593 100644 --- a/src/Persisters/Collection/OneToManyPersister.php +++ b/src/Persisters/Collection/OneToManyPersister.php @@ -8,6 +8,8 @@ use Doctrine\Common\Collections\Criteria; use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Types\Type; +use Doctrine\ORM\EntityNotFoundException; +use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Utility\PersisterHelper; @@ -166,7 +168,10 @@ public function loadCriteria(PersistentCollection $collection, Criteria $criteri throw new BadMethodCallException('Filtering a collection by Criteria is not supported by this CollectionPersister.'); } - /** @throws DBALException */ + /** + * @throws EntityNotFoundException + * @throws MappingException + */ private function deleteEntityCollection(PersistentCollection $collection): int { $mapping = $collection->getMapping(); @@ -186,6 +191,13 @@ private function deleteEntityCollection(PersistentCollection $collection): int $statement = 'DELETE FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; + if ($targetClass->isInheritanceTypeSingleTable()) { + $discriminatorColumn = $targetClass->getDiscriminatorColumn(); + $statement .= ' AND ' . $discriminatorColumn['name'] . ' = ?'; + $parameters[] = $targetClass->discriminatorValue; + $types[] = $discriminatorColumn['type']; + } + $numAffected = $this->conn->executeStatement($statement, $parameters, $types); assert(is_int($numAffected)); diff --git a/tests/Tests/ORM/Functional/Ticket/GH11500Test.php b/tests/Tests/ORM/Functional/Ticket/GH11500Test.php new file mode 100644 index 00000000000..d00a51e307b --- /dev/null +++ b/tests/Tests/ORM/Functional/Ticket/GH11500Test.php @@ -0,0 +1,109 @@ +setUpEntitySchema([ + GH11500AbstractTestEntity::class, + GH11500TestEntity::class, + GH11500TestEntityHolder::class, + ]); + } + + public function testDeleteOneToManyCollectionWithSingleTableInheritance(): void + { + $em = $this->getTestEntityManager(); + $conn = $em->getConnection(); + assert($conn instanceof ConnectionMock); + + $testEntity = new GH11500TestEntity(); + $testEntityHolder = new GH11500TestEntityHolder(); + + $testEntity->testEntityHolder = $testEntityHolder; + $testEntityHolder->testEntities->add($testEntity); + + $em->persist($testEntity); + $em->persist($testEntityHolder); + $em->flush(); + + assert($testEntityHolder->testEntities instanceof PersistentCollection); + + $persister = new OneToManyPersister($em); + $persister->delete($testEntityHolder->testEntities); + + $updates = $conn->getExecuteStatements(); + $lastStatement = array_pop($updates); + + self::assertEquals('DELETE FROM one_to_many_single_table_inheritance_test_entities WHERE test_entity_holder_id = ? AND type = ?', $lastStatement['sql']); + self::assertEquals('test_entity', $lastStatement['params'][1] ?? null); + } +} + + + +/** + * @ORM\Entity + * @ORM\Table(name="one_to_many_single_table_inheritance_test_entities") + * @ORM\InheritanceType("SINGLE_TABLE") + * @ORM\DiscriminatorColumn(name="type", type="string") + * @ORM\DiscriminatorMap({"test_entity"="GH11500TestEntity"}) + */ +class GH11500AbstractTestEntity +{ + /** + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue + */ + public int $id; +} + + +/** @ORM\Entity */ +class GH11500TestEntity extends GH11500AbstractTestEntity +{ + /** + * @ORM\ManyToOne(targetEntity="GH11500TestEntityHolder", inversedBy="testEntities") + * @ORM\JoinColumn(name="test_entity_holder_id", referencedColumnName="id") + */ + public GH11500TestEntityHolder $testEntityHolder; +} + +/** @ORM\Entity */ +class GH11500TestEntityHolder +{ + /** + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue + */ + public int $id; + + /** + * @ORM\OneToMany(targetEntity="GH11500TestEntity", mappedBy="testEntityHolder", orphanRemoval=true) + */ + public Collection $testEntities; + + public function __construct() + { + $this->testEntities = new ArrayCollection(); + } +}