Skip to content

Commit 8cb3e36

Browse files
committed
Fixed n+1 query bug when eager-loading elements on nested entries
- Element::eagerLoadingMap() calls EagerLoadingFieldInterface::getFieldLayout() for each source element - Entry::getFieldLayout() calls $this->getType() - Entry::getType() calls $this->getAvailableEntryTypes() - Entry::getAvailableEntryTypes() calls $this->getField() - NestedElementTrait::getField() calls $this->getOwner() - NestedElementTrait::getOwner() (or getPrimaryOwner()) executes queries to fetch the owner type and then the owner. Solution is to have getOwner() and getPrimaryOwner() eager-load the owner element onto all of the nested elements that were queried together, rather than just the current one. So the data is already in place for each of the following source elements.
1 parent ddbcc6f commit 8cb3e36

2 files changed

Lines changed: 49 additions & 36 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Fixed a bug where Color fields’ custom color inputs were including presets based on the color palette.
88
- Fixed a bug where nested Matrix entries weren’t getting assigned a post date if they were created while saving the owner element with a custom validation scenario. ([#16504](https://github.com/craftcms/cms/pull/16504))
99
- Fixed a bug where plugin settings pages weren’t displaying a read-only notice and had Save buttons, when `allowAdminChanges` was `false`. ([#16509](https://github.com/craftcms/cms/pull/16509))
10+
- Fixed a bug where eager-loading elements on nested entries resulted in a large number of database queries.
1011

1112
## 5.6.1 - 2025-01-22
1213

src/base/NestedElementTrait.php

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -164,25 +164,31 @@ public function getPrimaryOwner(): ?ElementInterface
164164
return null;
165165
}
166166

167-
$ownerType = $this->ownerType();
168-
if (!$ownerType) {
169-
return null;
170-
}
167+
if (isset($this->elementQueryResult)) {
168+
// Eager-load the primary owner for each of the elements in the result,
169+
// as we're probably going to end up needing them too
170+
Craft::$app->getElements()->eagerLoadElements($this::class, $this->elementQueryResult, ['primaryOwner']);
171+
} else {
172+
$ownerType = $this->ownerType();
173+
if (!$ownerType) {
174+
return null;
175+
}
171176

172-
$this->_primaryOwner = $ownerType::find()
173-
->id($primaryOwnerId)
174-
->site('*')
175-
->preferSites([$this->siteId])
176-
->unique()
177-
->status(null)
178-
->drafts(null)
179-
->provisionalDrafts(null)
180-
->revisions(null)
181-
->trashed(null)
182-
->one() ?? false;
183-
184-
if (!$this->_primaryOwner) {
185-
throw new InvalidConfigException("Invalid owner ID: $primaryOwnerId");
177+
$this->_primaryOwner = $ownerType::find()
178+
->id($primaryOwnerId)
179+
->site('*')
180+
->preferSites([$this->siteId])
181+
->unique()
182+
->status(null)
183+
->drafts(null)
184+
->provisionalDrafts(null)
185+
->revisions(null)
186+
->trashed(null)
187+
->one() ?? false;
188+
189+
if (!$this->_primaryOwner) {
190+
throw new InvalidConfigException("Invalid owner ID: $primaryOwnerId");
191+
}
186192
}
187193
}
188194

@@ -230,25 +236,31 @@ public function getOwner(): ?ElementInterface
230236
return $this->getPrimaryOwner();
231237
}
232238

233-
$ownerType = $this->ownerType();
234-
if (!$ownerType) {
235-
return null;
236-
}
239+
if (isset($this->elementQueryResult)) {
240+
// Eager-load the owner for each of the elements in the result,
241+
// as we're probably going to end up needing them too
242+
Craft::$app->getElements()->eagerLoadElements($this::class, $this->elementQueryResult, ['owner']);
243+
} else {
244+
$ownerType = $this->ownerType();
245+
if (!$ownerType) {
246+
return null;
247+
}
237248

238-
$this->_owner = $ownerType::find()
239-
->id($ownerId)
240-
->site('*')
241-
->preferSites([$this->siteId])
242-
->unique()
243-
->status(null)
244-
->drafts(null)
245-
->provisionalDrafts(null)
246-
->revisions(null)
247-
->trashed(null)
248-
->one() ?? false;
249-
250-
if (!$this->_owner) {
251-
throw new InvalidConfigException("Invalid owner ID: $ownerId");
249+
$this->_owner = $ownerType::find()
250+
->id($ownerId)
251+
->site('*')
252+
->preferSites([$this->siteId])
253+
->unique()
254+
->status(null)
255+
->drafts(null)
256+
->provisionalDrafts(null)
257+
->revisions(null)
258+
->trashed(null)
259+
->one() ?? false;
260+
261+
if (!$this->_owner) {
262+
throw new InvalidConfigException("Invalid owner ID: $ownerId");
263+
}
252264
}
253265
}
254266

0 commit comments

Comments
 (0)