PERSISTENCE FEATURE
N+1 Without Magic
No magic, no lazy loading, no bloated entity graphs. A screen asks for one slice, the ORM hydrates exactly that slice.
Feature Guide
A quick orientation block that answers the essential questions: what this feature does, how it works, why it matters, and the key concepts behind it.
What this does
Semitexa avoids N+1 by letting each screen define the exact table slice it needs, then batch-loading explicit relations for the whole result set.
How it works
You can model multiple resource abstractions over the same table. A slim list resource selects only the required columns, and the ResourceModel relation loader batch-loads explicit relations for all hydrated rows in one pass instead of per-row lazy lookups.
Why it matters
This removes the usual ORM trade-off between over-fetching giant entities and hiding extra queries behind lazy loading. The fetch plan is explicit, reviewable, and stable under load.
Key concepts
- N+1
- A query anti-pattern where one base query triggers one extra query per returned row.
- ResourceModelRelationLoader
- Batch-loads explicit relations once for the whole result set on the ResourceModel layer.
- Resource slice
- A narrow resource abstraction over a table containing only the columns and relations required by one use case.
No Magic, No Problem
N+1 solved by shaping the model, not hiding the database
Semitexa does not need lazy-loading theater to avoid N+1. A list page can define a small resource slice for one table, then batch-load only the relations it really needs for that screen.
The usual pain
- In other ORMs, fat-entity models often over-fetch columns first, then hide follow-up queries behind property access.
- Implicit relation loading can make local code look simple while database traffic quietly scales with the number of rows on screen.
- Traditionally this is handled with heavier fetch plans, special loading modes, or proxy behavior that becomes hard to reason about.
1 base query + 12 lazy category/review lookups
Query count grows with the number of rendered rows.
1 product slice query + 1 batch relation query
The fetch plan stays explicit and stable.
| Selected column | Why it belongs in the slice | Ownership |
|---|---|---|
id |
Needed for identity and links. | Card slice |
name |
Rendered on the list card. | Card slice |
price |
Displayed immediately in the UI. | Card slice |
category_id |
Enough to batch-resolve category when needed. | Card slice |
Verified against Semitexa Ultimate 2026.09.19.1020
N+1 Without Magic
Instead of a single fat entity with lazy-loaded relations, Semitexa uses screen-specific resource slices that declare exactly the columns they need. Relations are batch-loaded explicitly.
How it works
A screen defines its own ResourceModel subclass — for example ProductCardResource — pointing at the same table via #[FromTable] but declaring only the four columns it renders. If the screen also needs related data, ResourceModelRelationLoader batch-loads all related rows for the full result set in a second query, never one per row. There are no proxies and no lazy property access.
Why this matters
Implicit lazy loading makes local code look simple while database traffic scales silently with row count. An explicit resource slice keeps the fetch plan visible in code review, stable in production, and free from the runtime surprises that fat-entity ORMs introduce when a new template starts touching a previously unloaded property.
How it works
You can model multiple resource abstractions over the same table. A slim list resource selects only the required columns, and the ResourceModel relation loader batch-loads explicit relations for all hydrated rows in one pass instead of per-row lazy lookups.
Why it matters
This removes the usual ORM trade-off between over-fetching giant entities and hiding extra queries behind lazy loading. The fetch plan is explicit, reviewable, and stable under load.
Key concepts
- N+1
- A query anti-pattern where one base query triggers one extra query per returned row.
- ResourceModelRelationLoader
- Batch-loads explicit relations once for the whole result set on the ResourceModel layer.
- Resource slice
- A narrow resource abstraction over a table containing only the columns and relations required by one use case.