Skip to content

Commit aead77d

Browse files
FeoliusIvanStrygin
andauthored
Put actual value instead of index inside $originalEntityData. (#9244)
This fixes a bug with redundant UPDATE queries, that are executed when some entity uses foreign index of other entity as a primary key. This happens when after inserting related entities with $em->flush() call, you do the second $em->flush() without changing any data inside entities. Fixes GH8217. Co-authored-by: ivan <[email protected]>
1 parent f6e1dd4 commit aead77d

File tree

2 files changed

+113
-3
lines changed

2 files changed

+113
-3
lines changed

lib/Doctrine/ORM/UnitOfWork.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,14 +1166,16 @@ private function addToEntityIdentifiersAndEntityMap(
11661166
$identifier = [];
11671167

11681168
foreach ($class->getIdentifierFieldNames() as $idField) {
1169-
$value = $class->getFieldValue($entity, $idField);
1169+
$origValue = $class->getFieldValue($entity, $idField);
11701170

1171+
$value = null;
11711172
if (isset($class->associationMappings[$idField])) {
11721173
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
1173-
$value = $this->getSingleIdentifierValue($value);
1174+
$value = $this->getSingleIdentifierValue($origValue);
11741175
}
11751176

1176-
$identifier[$idField] = $this->originalEntityData[$oid][$idField] = $value;
1177+
$identifier[$idField] = $value ?? $origValue;
1178+
$this->originalEntityData[$oid][$idField] = $origValue;
11771179
}
11781180

11791181
$this->entityStates[$oid] = self::STATE_MANAGED;
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket;
6+
7+
use Doctrine\Common\Collections\ArrayCollection;
8+
use Doctrine\Common\Collections\Collection;
9+
use Doctrine\ORM\Mapping\Column;
10+
use Doctrine\ORM\Mapping\Entity;
11+
use Doctrine\ORM\Mapping\GeneratedValue;
12+
use Doctrine\ORM\Mapping\Id;
13+
use Doctrine\ORM\Mapping\JoinColumn;
14+
use Doctrine\ORM\Mapping\ManyToOne;
15+
use Doctrine\ORM\Mapping\OneToMany;
16+
use Doctrine\Tests\OrmFunctionalTestCase;
17+
18+
use function count;
19+
20+
final class GH8217Test extends OrmFunctionalTestCase
21+
{
22+
protected function setUp(): void
23+
{
24+
parent::setUp();
25+
$this->setUpEntitySchema(
26+
[
27+
GH8217Collection::class,
28+
GH8217CollectionItem::class,
29+
]
30+
);
31+
}
32+
33+
/**
34+
* @group GH-8217
35+
*/
36+
public function testNoQueriesAfterSecondFlush(): void
37+
{
38+
$collection = new GH8217Collection();
39+
$collection->addItem(new GH8217CollectionItem($collection, 0));
40+
$collection->addItem(new GH8217CollectionItem($collection, 1));
41+
$this->_em->persist($collection);
42+
$this->_em->flush();
43+
44+
$logger = $this->_sqlLoggerStack;
45+
$queriesNumberBeforeSecondFlush = count($logger->queries);
46+
$this->_em->flush();
47+
$queriesNumberAfterSecondFlush = count($logger->queries);
48+
self::assertEquals($queriesNumberBeforeSecondFlush, $queriesNumberAfterSecondFlush);
49+
}
50+
}
51+
52+
/**
53+
* @Entity
54+
*/
55+
class GH8217Collection
56+
{
57+
/**
58+
* @var int
59+
* @Id
60+
* @Column(type="integer")
61+
* @GeneratedValue
62+
*/
63+
public $id;
64+
65+
/**
66+
* @psalm-var Collection<int, GH8217CollectionItem>
67+
* @OneToMany(targetEntity="GH8217CollectionItem", mappedBy="collection",
68+
* cascade={"persist", "remove"}, orphanRemoval=true)
69+
*/
70+
public $items;
71+
72+
public function __construct()
73+
{
74+
$this->items = new ArrayCollection();
75+
}
76+
77+
public function addItem(GH8217CollectionItem $item): void
78+
{
79+
$this->items->add($item);
80+
}
81+
}
82+
83+
/**
84+
* @Entity
85+
*/
86+
class GH8217CollectionItem
87+
{
88+
/**
89+
* @var GH8217Collection
90+
* @Id
91+
* @ManyToOne(targetEntity="GH8217Collection", inversedBy="items")
92+
* @JoinColumn(name="id", referencedColumnName="id")
93+
*/
94+
public $collection;
95+
96+
/**
97+
* @var int
98+
* @Id
99+
* @Column(type="integer", options={"unsigned": true})
100+
*/
101+
public $collectionIndex;
102+
103+
public function __construct(GH8217Collection $collection, int $collectionIndex)
104+
{
105+
$this->collection = $collection;
106+
$this->collectionIndex = $collectionIndex;
107+
}
108+
}

0 commit comments

Comments
 (0)