Skip to content

Commit e38278b

Browse files
authored
Fix eager fetch composite foreign key (#11397)
I think #11289 did not completely fix problem for eager fetch. Change in that PR checked if primary key of target class is composite but that does not matter when loading collection by foreign key. It should check if foreign key on target class is composite. Fix from that PR did not work for me because i had entity with regular autogenerated id (single column), but foreign key referenced entity with composite primary key, like SecondLevelWithoutCompositePrimaryKey in this PR. Checking if foreign key is composite fixed the problem for me.
1 parent 5bff091 commit e38278b

File tree

4 files changed

+61
-6
lines changed

4 files changed

+61
-6
lines changed

src/UnitOfWork.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
use function array_sum;
6363
use function array_values;
6464
use function assert;
65+
use function count;
6566
use function current;
6667
use function func_get_arg;
6768
use function func_num_args;
@@ -3172,8 +3173,10 @@ public function createEntity($className, array $data, &$hints = [])
31723173
$reflField->setValue($entity, $pColl);
31733174

31743175
if ($hints['fetchMode'][$class->name][$field] === ClassMetadata::FETCH_EAGER) {
3175-
$isIteration = isset($hints[Query::HINT_INTERNAL_ITERATION]) && $hints[Query::HINT_INTERNAL_ITERATION];
3176-
if ($assoc['type'] === ClassMetadata::ONE_TO_MANY && ! $isIteration && ! $targetClass->isIdentifierComposite && ! isset($assoc['indexBy'])) {
3176+
$isIteration = isset($hints[Query::HINT_INTERNAL_ITERATION]) && $hints[Query::HINT_INTERNAL_ITERATION];
3177+
$isForeignKeyComposite = $targetClass->hasAssociation($assoc['mappedBy']) && count($targetClass->getAssociationMapping($assoc['mappedBy'])['joinColumns'] ?? []) > 1;
3178+
3179+
if ($assoc['type'] === ClassMetadata::ONE_TO_MANY && ! $isIteration && ! $isForeignKeyComposite && ! isset($assoc['indexBy'])) {
31773180
$this->scheduleCollectionForBatchLoading($pColl, $class);
31783181
} else {
31793182
$this->loadCollection($pColl);

tests/Tests/Models/EagerFetchedCompositeOneToMany/RootEntity.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,19 @@ class RootEntity
3737
*/
3838
private $secondLevel;
3939

40+
/**
41+
* @ORM\OneToMany(mappedBy="root", targetEntity=SecondLevelWithoutCompositePrimaryKey::class, fetch="EAGER")
42+
*
43+
* @var Collection<int, SecondLevelWithoutCompositePrimaryKey>
44+
*/
45+
private $anotherSecondLevel;
46+
4047
public function __construct(int $id, string $other)
4148
{
42-
$this->otherKey = $other;
43-
$this->secondLevel = new ArrayCollection();
44-
$this->id = $id;
49+
$this->otherKey = $other;
50+
$this->secondLevel = new ArrayCollection();
51+
$this->anotherSecondLevel = new ArrayCollection();
52+
$this->id = $id;
4553
}
4654

4755
public function getId(): ?int
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\Models\EagerFetchedCompositeOneToMany;
6+
7+
use Doctrine\ORM\Mapping as ORM;
8+
9+
/**
10+
* @ORM\Entity
11+
*/
12+
class SecondLevelWithoutCompositePrimaryKey
13+
{
14+
/**
15+
* @ORM\Id
16+
* @ORM\GeneratedValue
17+
* @ORM\Column(type="integer", nullable=false)
18+
*
19+
* @var int|null
20+
*/
21+
private $id;
22+
23+
/**
24+
* @ORM\ManyToOne(targetEntity=RootEntity::class, inversedBy="anotherSecondLevel")
25+
* @ORM\JoinColumns({
26+
* @ORM\JoinColumn(name="root_id", referencedColumnName="id"),
27+
* @ORM\JoinColumn(name="root_other_key", referencedColumnName="other_key")
28+
* })
29+
*
30+
* @var RootEntity
31+
*/
32+
private $root;
33+
34+
public function __construct(RootEntity $upper)
35+
{
36+
$this->root = $upper;
37+
}
38+
39+
public function getId(): ?int
40+
{
41+
return $this->id;
42+
}
43+
}

tests/Tests/ORM/Functional/EagerFetchOneToManyWithCompositeKeyTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
use Doctrine\Tests\Models\EagerFetchedCompositeOneToMany\RootEntity;
88
use Doctrine\Tests\Models\EagerFetchedCompositeOneToMany\SecondLevel;
9+
use Doctrine\Tests\Models\EagerFetchedCompositeOneToMany\SecondLevelWithoutCompositePrimaryKey;
910
use Doctrine\Tests\OrmFunctionalTestCase;
1011

1112
final class EagerFetchOneToManyWithCompositeKeyTest extends OrmFunctionalTestCase
1213
{
1314
/** @ticket 11154 */
1415
public function testItDoesNotThrowAnExceptionWhenTriggeringALoad(): void
1516
{
16-
$this->setUpEntitySchema([RootEntity::class, SecondLevel::class]);
17+
$this->setUpEntitySchema([RootEntity::class, SecondLevel::class, SecondLevelWithoutCompositePrimaryKey::class]);
1718

1819
$a1 = new RootEntity(1, 'A');
1920

0 commit comments

Comments
 (0)