Skip to content

jmix-configure-fetch-plan: fetch="BATCH" does not remove N+1 for nested collections #46

Description

@Fedoseew

Found while following the skill on a Jmix 3.0.1 project.

Problem: wrong — the stated benefit does not hold in this configuration.

Task

Paginated read of Order entities for a list endpoint, each with its orderLines collection and the product of every line.

Where

The "Fetch Modes" section, whose table states: BATCH — loads references in a separate IN-clause query; best for to-many collections (avoids N+1).

What happened

The mode really is applied — the framework's own DEBUG log for its fetch-group manager reports e.orderLines=BATCH — but EclipseLink still reads the collection with one query per parent, ... WHERE ORDER_ID = ? repeated for every row of the page. The reason is that the plan is installed as a LOAD_GROUP rather than a FETCH_GROUP: a plan built with FetchPlanBuilder always takes that path, because loadPartialEntities() is false for it, and calling partial() does not change the measurement either. What did work was removing the collection from the fetch plan and loading it for the whole page with one repository query (... in :ids): a page of 10 parents went from 322 SQL statements to 28, and the count stopped growing with page size. Caught by measuring executed SQL at runtime — no gate reports this, since the code compiles, passes the IDE inspection, and passes a green clean test.

Also seen

FetchMode.JOIN on a to-one nested inside a collection that is itself marked FetchMode.BATCH makes EclipseLink throw NullPointerException: Cannot invoke "java.util.Collection.toArray()" because "c" is null when the query runs. The table presents JOIN and BATCH as freely combinable per property, so this combination looks legitimate. Compilation and the IDE inspection pass; only executing the query fails. Caught by runtime.

Suggested fix

In "Fetch Modes", say that for a nested collection the mode may have no effect, because the plan is applied as a LoadGroup, and that the reliable way to remove N+1 there is a separate batch query for the whole page rather than a fetch mode. Add to "Forbidden" that FetchMode.JOIN must not be set on a to-one nested inside a FetchMode.BATCH collection.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions