diff --git a/src/Persisters/Collection/OneToManyPersister.php b/src/Persisters/Collection/OneToManyPersister.php index f39415fc0c9..6769acca909 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,11 @@ public function loadCriteria(PersistentCollection $collection, Criteria $criteri throw new BadMethodCallException('Filtering a collection by Criteria is not supported by this CollectionPersister.'); } - /** @throws DBALException */ + /** + * @throws DBALException + * @throws EntityNotFoundException + * @throws MappingException + */ private function deleteEntityCollection(PersistentCollection $collection): int { $mapping = $collection->getMapping(); @@ -186,6 +192,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..4be3bf2b76e --- /dev/null +++ b/tests/Tests/ORM/Functional/Ticket/GH11500Test.php @@ -0,0 +1,137 @@ +setUpEntitySchema([ + GH11500AbstractTestEntity::class, + GH11500TestEntityOne::class, + GH11500TestEntityTwo::class, + GH11500TestEntityHolder::class, + ]); + } + + /** + * @throws ORMException + */ + public function testDeleteOneToManyCollectionWithSingleTableInheritance(): void + { + $testEntityOne = new GH11500TestEntityOne(); + $testEntityTwo = new GH11500TestEntityTwo(); + $testEntityHolder = new GH11500TestEntityHolder(); + + $testEntityOne->testEntityHolder = $testEntityHolder; + $testEntityHolder->testEntityOnes->add($testEntityOne); + + $testEntityTwo->testEntityHolder = $testEntityHolder; + $testEntityHolder->testEntityTwos->add($testEntityTwo); + + $em = $this->getEntityManager(); + $em->persist($testEntityOne); + $em->persist($testEntityTwo); + $em->persist($testEntityHolder); + $em->flush(); + + $testEntityTwosBeforeRemovalOfTestEntityOnes = $testEntityHolder->testEntityTwos->toArray(); + + $testEntityHolder->testEntityOnes = new ArrayCollection(); + $em->persist($testEntityHolder); + $em->flush(); + $em->refresh($testEntityHolder); + + static::assertEmpty($testEntityHolder->testEntityOnes->toArray(), 'All records should have been deleted'); + static::assertEquals($testEntityTwosBeforeRemovalOfTestEntityOnes, $testEntityHolder->testEntityTwos->toArray(), 'Different Entity\'s records should not have been deleted'); + } +} + + + +/** + * @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_one"="GH11500TestEntityOne", "test_entity_two"="GH11500TestEntityTwo"}) + */ +class GH11500AbstractTestEntity +{ + /** + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue + * + * @var int + */ + public $id; +} + + +/** @ORM\Entity */ +class GH11500TestEntityOne extends GH11500AbstractTestEntity +{ + /** + * @ORM\ManyToOne(targetEntity="GH11500TestEntityHolder", inversedBy="testEntityOnes") + * @ORM\JoinColumn(name="test_entity_holder_id", referencedColumnName="id") + * + * @var GH11500TestEntityHolder + */ + public $testEntityHolder; +} + +/** @ORM\Entity */ +class GH11500TestEntityTwo extends GH11500AbstractTestEntity +{ + /** + * @ORM\ManyToOne(targetEntity="GH11500TestEntityHolder", inversedBy="testEntityTwos") + * @ORM\JoinColumn(name="test_entity_holder_id", referencedColumnName="id") + * + * @var GH11500TestEntityHolder + */ + public $testEntityHolder; +} + +/** @ORM\Entity */ +class GH11500TestEntityHolder +{ + /** + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue + * + * @var int + */ + public $id; + + /** + * @ORM\OneToMany(targetEntity="GH11500TestEntityOne", mappedBy="testEntityHolder", orphanRemoval=true) + * + * @var Collection + */ + public $testEntityOnes; + + /** + * @ORM\OneToMany(targetEntity="GH11500TestEntityTwo", mappedBy="testEntityHolder", orphanRemoval=true) + * + * @var Collection + */ + public $testEntityTwos; + + public function __construct() + { + $this->testEntityOnes = new ArrayCollection(); + $this->testEntityTwos = new ArrayCollection(); + } +}