Skip to content

Perf: HasMany/BelongsToMany/HasOne setValue queries the RelationBuilder instead of the loaded relation #160

Description

@ginkelsoft-development

Probleem

Bij audit van #132 viel op dat de N+1 niet in `RowFormatter` zit (die werkt op een al gehydrateerd resource), maar in de `setValue()` overrides van de relation-fields. Voorbeeld in `HasManyField::setValue()`:

```php
$relation = $model->{$this->name}(); // ← RelationBuilder

if ($relation instanceof HasMany) {
$this->value = $relation
->pluck("{$table}.{$displayColumn}", "{$table}.{$returnColumn}")
->toArray(); // ← triggers a NEW query per record
}
```

`pluck()` op een `RelationBuilder` (van `$model->relation()`) voert altijd een nieuwe query uit. Eager-loading upstream (`with('relation')`, `loadMissing(...)`) is hier nutteloos — pluck negeert de loaded data.

Impact: datatable van 25 rijen × 1 HasManyField = 25 extra queries per pagina, ook al is de relation al eager-geladen.

Welke fields

  • `HasManyField::setValue()`
  • `BelongsToManyField::setValue()`
  • `HasOneField::setValue()` — als deze pluck/get gebruikt (te verifiëren)

Voorgestelde fix

```php
$items = $model->relationLoaded($this->name)
? $model->getRelation($this->name)
: $relation->get();
$this->value = $items
->pluck($this->displayColumn, $this->returnColumn)
->toArray();
```

`pluck` op een Collection werkt zonder table-prefix (gewoon op array keys), dus de `"{$table}.{$column}"` formattering moet weg.

Aanvullend: in `BuildoraDatatable::formatRecords()` (relation-mode) een `(new Collection($records))->loadMissing($relations)` toevoegen vóór de `fill()` loop, zodat de relations daadwerkelijk al geladen zijn voordat setValue ze raadpleegt.

Acceptatiecriteria

  • 3 field-types setValue gebruikt loaded relation als beschikbaar
  • BuildoraDatatable::formatRecords doet upfront loadMissing voor model-records
  • Query log voor datatable met HasMany column: aantal queries onafhankelijk van rij-aantal (i.p.v. lineair)
  • Regression tests die N+1 vangen (count queries via `DB::enableQueryLog()`)

Context

Issue #132 is gesloten ten gunste van deze meer chirurgische follow-up.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions