diff --git a/src/UnitOfWork.php b/src/UnitOfWork.php index 609bea433f..f1affcf7eb 100644 --- a/src/UnitOfWork.php +++ b/src/UnitOfWork.php @@ -1292,6 +1292,8 @@ private function executeDeletions(): void $eventsToDispatch = []; foreach ($entities as $entity) { + $this->removeFromIdentityMap($entity); + $oid = spl_object_id($entity); $class = $this->em->getClassMetadata(get_class($entity)); $persister = $this->getEntityPersister($class->name); @@ -1667,8 +1669,6 @@ public function scheduleForDelete($entity) return; } - $this->removeFromIdentityMap($entity); - unset($this->entityUpdates[$oid]); if (! isset($this->entityDeletions[$oid])) { diff --git a/tests/Tests/ORM/Functional/Ticket/GH6123Test.php b/tests/Tests/ORM/Functional/Ticket/GH6123Test.php new file mode 100644 index 0000000000..7a5f14980f --- /dev/null +++ b/tests/Tests/ORM/Functional/Ticket/GH6123Test.php @@ -0,0 +1,80 @@ +createSchemaForModels( + GH6123Entity::class, + ); + } + + public function testLoadingRemovedEntityFromDatabaseDoesNotCreateNewManagedEntityInstance(): void + { + $entity = new GH6123Entity(); + $this->_em->persist($entity); + $this->_em->flush(); + + self::assertSame(UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($entity)); + self::assertFalse($this->_em->getUnitOfWork()->isScheduledForDelete($entity)); + + $this->_em->remove($entity); + + $freshEntity = $this->loadEntityFromDatabase($entity->id); + self::assertSame($entity, $freshEntity); + + self::assertSame(UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($freshEntity)); + self::assertTrue($this->_em->getUnitOfWork()->isScheduledForDelete($freshEntity)); + } + + public function testRemovedEntityCanBePersistedAgain(): void + { + $entity = new GH6123Entity(); + $this->_em->persist($entity); + $this->_em->flush(); + + $this->_em->remove($entity); + self::assertSame(UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($entity)); + self::assertTrue($this->_em->getUnitOfWork()->isScheduledForDelete($entity)); + + $this->loadEntityFromDatabase($entity->id); + + $this->_em->persist($entity); + self::assertSame(UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($entity)); + self::assertFalse($this->_em->getUnitOfWork()->isScheduledForDelete($entity)); + + $this->_em->flush(); + } + + private function loadEntityFromDatabase(int $id): GH6123Entity|null + { + return $this->_em->createQueryBuilder() + ->select('e') + ->from(GH6123Entity::class, 'e') + ->where('e.id = :id') + ->setParameter('id', $id) + ->getQuery() + ->getOneOrNullResult(); + } +} + +#[ORM\Entity] +class GH6123Entity +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[Column(type: Types::INTEGER, nullable: false)] + public int $id; +} diff --git a/tests/Tests/ORM/UnitOfWorkTest.php b/tests/Tests/ORM/UnitOfWorkTest.php index 0569bfd06d..ee475e729d 100644 --- a/tests/Tests/ORM/UnitOfWorkTest.php +++ b/tests/Tests/ORM/UnitOfWorkTest.php @@ -413,12 +413,18 @@ public function testRemovedAndRePersistedEntitiesAreInTheIdentityMapAndAreNotGar $entity->id = 123; $this->_unitOfWork->registerManaged($entity, ['id' => 123], []); + self::assertSame(UnitOfWork::STATE_MANAGED, $this->_unitOfWork->getEntityState($entity)); + self::assertFalse($this->_unitOfWork->isScheduledForDelete($entity)); self::assertTrue($this->_unitOfWork->isInIdentityMap($entity)); $this->_unitOfWork->remove($entity); - self::assertFalse($this->_unitOfWork->isInIdentityMap($entity)); + self::assertSame(UnitOfWork::STATE_REMOVED, $this->_unitOfWork->getEntityState($entity)); + self::assertTrue($this->_unitOfWork->isScheduledForDelete($entity)); + self::assertTrue($this->_unitOfWork->isInIdentityMap($entity)); $this->_unitOfWork->persist($entity); + self::assertSame(UnitOfWork::STATE_MANAGED, $this->_unitOfWork->getEntityState($entity)); + self::assertFalse($this->_unitOfWork->isScheduledForDelete($entity)); self::assertTrue($this->_unitOfWork->isInIdentityMap($entity)); }