Hibernate HQL join fetch not recursively fetching

Your EAGER mapping will only be considered automatically by Hibernate if you use the Criteria API for the query.

If you use HQL, you will need to manually add the FETCH keyword to your JOINs to force Hibernate to include the relations in the first query and avoid subsequent queries.

This is Hibernate-specific and may work differently on other ORMs.

See this question/answer for a slightly different angle.


You marked your associations EAGER. So, whatever you do in your query, Hibernate will load all the associated domains and network codes of the loaded domains. And it will load the domains and network codes of the additional domains, etc. etc. until all collection loads return empty collections or entities that have already been loaded.

To avoid that, make your collections lazy (as they are by default). Then loading a domain with its operators and its network codes will load just that.


If you know that you have only two levels in your tree, have you thought of joining deeper one level. Something like below?

SELECT DISTINCT domain FROM Domain domain 
  LEFT OUTER JOIN FETCH domain.operators operators1 
  LEFT OUTER JOIN FETCH domain.networkCodes 
  LEFT OUTER JOIN FETCH operators1.operators operators2 
  LEFT OUTER JOIN FETCH operators1.networkCodes
WHERE domain.domainId = :domainId

The Hibernate Relations Works with different Fetch Strategies..!!

Hibernate provides 4 strategies for retrieving data:

SELECT

@OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
@Column(name="id") 
@Fetch(FetchMode.SELECT)

In this Method there are Multiple SQLs fired. This first one is fired for retrieving all the records in the Parent table. The remaining are fired for retrieving records for each Parent Record. This is basically the N+1 problem. The first query retrieves N records from database, in this case N Parent records. For each Parent a new query retrieves Child. Therefore for N Parent, N queries retrieve information from Child table.

JOIN

@OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
@Column(name="id")
@Fetch(FetchMode.JOIN) 

This is similar to the SELECT fetch strategy except that fact that all database retrieval take place upfront in JOIN fetch unlike in SELECT where it happens on a need basis. This can become an important performance consideration.

SUBSELECT

 @OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
 @Column(name="id")
 @Fetch(FetchMode.SUBSELECT)

Two SQLs are fired. One to retrieve all Parent and the second uses a SUBSELECT query in the WHERE clause to retrieve all child that has matching parent ids.

BATCH

@OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
@Column(name="id")
@@BatchSize(size=2)

The batch size maps to the number of Parent whose child are retrieved. So we can specify the number of records to be fetched at a time.But Multiple queries will be executed.!!

one-to-many & many-to-many allows - join, Select and SubSelect

many-to-one & one-to-one allows - Join and Select


Hibernate also distinguishes between (when is the associations are fetched)

1.Immediate fetching -

an association, collection or attribute is fetched immediately, when the Parent is loaded. (lazy=“false”)

2.Lazy collection fetching -

a collection is fetched when the application invokes an operation upon that collection. (This is the default for collections.(lazy=“true”)

3."Extra-lazy" collection fetching -

individual elements of the collection are accessed from the database as needed. Hibernate tries not to fetch the whole collection into memory unless absolutely needed (suitable for very large collections) (lazy=“extra”)

4.Proxy fetching -

a single-valued association is fetched when a method other than the identifier getter is invoked upon the associated object. (lazy=“proxy”)

5."No-proxy" fetching -

a single-valued association is fetched when the instance variable is accessed. Compared to proxy fetching, this approach is less lazy.(lazy=“no-proxy”)

6.Lazy attribute fetching -

an attribute or single valued association is fetched when the instance variable is accessed. (lazy=“true”)

one-to-many & many-to-many allows Immediate, Layzy, Extra Lazy

many-to-one & one-to-one allows Immediate Proxy, No Proxy