-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Original entity data resolves inverse 1-1 joins
If the source entity for an inverse (non-owning) 1-1 relationship is identified by an association then the identifying association may not be set when an inverse one-to-one association is resolved. This means that no data is available in the entity to resolve the needed column value for the join query. The original entity data can be retrieved from the unit of work and is used as a fallback to populate the query condition. Fixes #11108
- Loading branch information
Showing
5 changed files
with
204 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
tests/Tests/Models/OneToOneInverseSideWithAssociativeIdLoad/InverseSide.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\Tests\Models\OneToOneInverseSideWithAssociativeIdLoad; | ||
|
||
use Doctrine\ORM\Mapping\Entity; | ||
use Doctrine\ORM\Mapping\Id; | ||
use Doctrine\ORM\Mapping\JoinColumn; | ||
use Doctrine\ORM\Mapping\OneToOne; | ||
use Doctrine\ORM\Mapping\Table; | ||
|
||
/** | ||
* @Entity() | ||
* @Table(name="one_to_one_inverse_side_assoc_id_load_inverse") | ||
*/ | ||
class InverseSide | ||
{ | ||
/** | ||
* Associative id (owning identifier) | ||
* | ||
* @var InverseSideIdTarget | ||
* @Id() | ||
* @OneToOne(targetEntity=InverseSideIdTarget::class, inversedBy="inverseSide") | ||
* @JoinColumn(nullable=false, name="associativeId") | ||
*/ | ||
public $associativeId; | ||
|
||
/** | ||
* @var OwningSide | ||
* @OneToOne(targetEntity=OwningSide::class, mappedBy="inverse") | ||
*/ | ||
public $owning; | ||
} |
33 changes: 33 additions & 0 deletions
33
tests/Tests/Models/OneToOneInverseSideWithAssociativeIdLoad/InverseSideIdTarget.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\Tests\Models\OneToOneInverseSideWithAssociativeIdLoad; | ||
|
||
use Doctrine\ORM\Mapping\Column; | ||
use Doctrine\ORM\Mapping\Entity; | ||
use Doctrine\ORM\Mapping\GeneratedValue; | ||
use Doctrine\ORM\Mapping\Id; | ||
use Doctrine\ORM\Mapping\OneToOne; | ||
use Doctrine\ORM\Mapping\Table; | ||
|
||
/** | ||
* @Entity() | ||
* @Table(name="one_to_one_inverse_side_assoc_id_load_inverse_id_target") | ||
*/ | ||
class InverseSideIdTarget | ||
{ | ||
/** | ||
* @var string | ||
* @Id() | ||
* @Column(type="string", length=255) | ||
* @GeneratedValue(strategy="NONE") | ||
*/ | ||
public $id; | ||
|
||
/** | ||
* @var InverseSide | ||
* @OneToOne(targetEntity=InverseSide::class, mappedBy="associativeId") | ||
*/ | ||
public $inverseSide; | ||
} |
37 changes: 37 additions & 0 deletions
37
tests/Tests/Models/OneToOneInverseSideWithAssociativeIdLoad/OwningSide.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\Tests\Models\OneToOneInverseSideWithAssociativeIdLoad; | ||
|
||
use Doctrine\ORM\Mapping\Column; | ||
use Doctrine\ORM\Mapping\Entity; | ||
use Doctrine\ORM\Mapping\GeneratedValue; | ||
use Doctrine\ORM\Mapping\Id; | ||
use Doctrine\ORM\Mapping\JoinColumn; | ||
use Doctrine\ORM\Mapping\OneToOne; | ||
use Doctrine\ORM\Mapping\Table; | ||
|
||
/** | ||
* @Entity() | ||
* @Table(name="one_to_one_inverse_side_assoc_id_load_owning") | ||
*/ | ||
class OwningSide | ||
{ | ||
/** | ||
* @var string | ||
* @Id() | ||
* @Column(type="string", length=255) | ||
* @GeneratedValue(strategy="NONE") | ||
*/ | ||
public $id; | ||
|
||
/** | ||
* Owning side | ||
* | ||
* @var InverseSide | ||
* @OneToOne(targetEntity=InverseSide::class, inversedBy="owning") | ||
* @JoinColumn(name="inverse", referencedColumnName="associativeId") | ||
*/ | ||
public $inverse; | ||
} |
68 changes: 68 additions & 0 deletions
68
tests/Tests/ORM/Functional/OneToOneInverseSideWithAssociativeIdLoadAfterDqlQueryTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\Tests\ORM\Functional; | ||
|
||
use Doctrine\Tests\Models\OneToOneInverseSideWithAssociativeIdLoad\InverseSide; | ||
use Doctrine\Tests\Models\OneToOneInverseSideWithAssociativeIdLoad\InverseSideIdTarget; | ||
use Doctrine\Tests\Models\OneToOneInverseSideWithAssociativeIdLoad\OwningSide; | ||
use Doctrine\Tests\OrmFunctionalTestCase; | ||
|
||
use function assert; | ||
|
||
class OneToOneInverseSideWithAssociativeIdLoadAfterDqlQueryTest extends OrmFunctionalTestCase | ||
{ | ||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
$this->createSchemaForModels(OwningSide::class, InverseSideIdTarget::class, InverseSide::class); | ||
} | ||
|
||
/** @group GH-11108 */ | ||
public function testInverseSideWithAssociativeIdOneToOneLoadedAfterDqlQuery(): void | ||
{ | ||
$owner = new OwningSide(); | ||
$inverseId = new InverseSideIdTarget(); | ||
$inverse = new InverseSide(); | ||
|
||
$owner->id = 'owner'; | ||
$inverseId->id = 'inverseId'; | ||
$inverseId->inverseSide = $inverse; | ||
$inverse->associativeId = $inverseId; | ||
$owner->inverse = $inverse; | ||
$inverse->owning = $owner; | ||
|
||
$this->_em->persist($owner); | ||
$this->_em->persist($inverseId); | ||
$this->_em->persist($inverse); | ||
$this->_em->flush(); | ||
$this->_em->clear(); | ||
|
||
$fetchedInverse = $this | ||
->_em | ||
->createQueryBuilder() | ||
->select('inverse') | ||
->from(InverseSide::class, 'inverse') | ||
->andWhere('inverse.associativeId = :associativeId') | ||
->setParameter('associativeId', 'inverseId') | ||
->getQuery() | ||
->getSingleResult(); | ||
assert($fetchedInverse instanceof InverseSide); | ||
|
||
self::assertInstanceOf(InverseSide::class, $fetchedInverse); | ||
self::assertInstanceOf(InverseSideIdTarget::class, $fetchedInverse->associativeId); | ||
self::assertInstanceOf(OwningSide::class, $fetchedInverse->owning); | ||
|
||
$this->assertSQLEquals( | ||
'select o0_.associativeid as associativeid_0 from one_to_one_inverse_side_assoc_id_load_inverse o0_ where o0_.associativeid = ?', | ||
$this->getLastLoggedQuery(1)['sql'] | ||
); | ||
|
||
$this->assertSQLEquals( | ||
'select t0.id as id_1, t0.inverse as inverse_2 from one_to_one_inverse_side_assoc_id_load_owning t0 where t0.inverse = ?', | ||
$this->getLastLoggedQuery()['sql'] | ||
); | ||
} | ||
} |