Pomůžu si citací ze specifikace (kapitola 4.4.5.3):
The following query returns a set of departments. As a side effect, the associated employees for those departments are also retrieved, even though they are not part of the explicit query result. The persistent fields or properties of the employees that are eagerly fetched are fully initialized. The initialization of the relationship properties of the employees that are retrieved is determined by the metadata for the Employee entity class.
SELECT d FROM Department d LEFT JOIN FETCH d.employees WHERE d.deptno = 1
A fetch join has the same join semantics as the corresponding inner or outer join, except that the related objects specified on the right-hand side of the join operation are not returned in the query result or otherwise referenced in the query. Hence, for example, if department 1 has five employees, the above query returns five references to the department 1 entity.
Za popsaných podmínek tedy tento dotaz vrátí 5 departmentů (5 krát ten samý), přestože department s číslem 1 existuje pouze jeden. Bez použití klauzule LEFT JOIN FETCH
by se vrátil jediný záznam. Zaměstnance by bylo defaultně nutné dotáhnout lenivě.
Citovaný text zároveň říká, že při vyhodnocení dotazu se korektně dotáhnou relace podle nastavení v anotacích. Mnou popsané chování Hibernate tedy pravděpodobně byl bug nějaké starší verze. Zkoušel jsem to znovu a nyní se skutečně Hibernate chová v souladu se specifikací, takže se omlouvám za mystifikaci.
A proč mi to připadalo logické? Protože mám možnost si explicitně referencované entity dotáhnout pomocí fetch joinu, pokud to potřebuji, nebo je nedotahovat, pokud to nepotřebuji. Automatické dotažení entit nemusí být vždy efektivní. Např. pokud ve výše uvedeném příkladu budu mít Employees dotahované eager, tak Hibernate udělá jeden dotaz na Department a potom bude postupně dotahovat Employees po skupinách o velikosti hibernate.default_batch_fetch_size
. Počet dotazů do DB je tedy lineárně závislý na počtu instancí entity Department. Tohle se žádnému DBA líbit nebude... Pokud se budou Employees dotahovat lenivě, tak se provede to samé, ale až při prvním přístupu ke kolekci Employees. Pokud tedy logika aplikace pracuje pouze s Departmenty, tak stačí jediný dotaz do DB.