diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index b9fb045e9..6152c4176 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -792,6 +792,8 @@ class BasicEntityPersister implements EntityPersister $sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']); $owningAssoc = $targetClass->getAssociationMapping($assoc['mappedBy']); + $computedIdentifier = []; + // TRICKY: since the association is specular source and target are flipped foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) { if ( ! isset($sourceClass->fieldNames[$sourceKeyColumn])) { @@ -800,15 +802,11 @@ class BasicEntityPersister implements EntityPersister ); } - // unset the old value and set the new sql aliased value here. By definition - // unset($identifier[$targetKeyColumn] works here with how UnitOfWork::createEntity() calls this method. - $identifier[$targetClass->getFieldForColumn($targetKeyColumn)] = + $computedIdentifier[$targetClass->getFieldForColumn($targetKeyColumn)] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity); - - unset($identifier[$targetKeyColumn]); } - $targetEntity = $this->load($identifier, null, $assoc); + $targetEntity = $this->load($computedIdentifier, null, $assoc); if ($targetEntity !== null) { $targetClass->setFieldValue($targetEntity, $assoc['mappedBy'], $sourceEntity); diff --git a/tests/Doctrine/Tests/Models/OneToOneInverseSideLoad/InverseSide.php b/tests/Doctrine/Tests/Models/OneToOneInverseSideLoad/InverseSide.php new file mode 100644 index 000000000..1b7d844b2 --- /dev/null +++ b/tests/Doctrine/Tests/Models/OneToOneInverseSideLoad/InverseSide.php @@ -0,0 +1,26 @@ +_schemaTool->createSchema([ + $this->_em->getClassMetadata(OwningSide::class), + $this->_em->getClassMetadata(InverseSide::class), + ]); + } catch(ToolsException $e) { + // ignored + } + } + + /** + * @group 6759 + */ + public function testInverseSideOneToOneLoadedAfterDqlQuery(): void + { + $owner = new OwningSide(); + $inverse = new InverseSide(); + + $owner->id = 'owner'; + $inverse->id = 'inverse'; + $owner->inverse = $inverse; + $inverse->owning = $owner; + + $this->_em->persist($owner); + $this->_em->persist($inverse); + $this->_em->flush(); + $this->_em->clear(); + + /* @var $fetchedInverse InverseSide */ + $fetchedInverse = $this + ->_em + ->createQueryBuilder() + ->select('inverse') + ->from(InverseSide::class, 'inverse') + ->andWhere('inverse.id = :id') + ->setParameter('id', 'inverse') + ->getQuery() + ->getSingleResult(); + + self::assertInstanceOf(InverseSide::class, $fetchedInverse); + self::assertInstanceOf(OwningSide::class, $fetchedInverse->owning); + + $this->assertSQLEquals( + 'select o0_.id as id_0 from one_to_one_inverse_side_load_inverse o0_ where o0_.id = ?', + $this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery - 1]['sql'] + ); + + $this->assertSQLEquals( + 'select t0.id as id_1, t0.inverse as inverse_2 from one_to_one_inverse_side_load_owning t0 WHERE t0.inverse = ?', + $this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql'] + ); + } +}