Eager subsequent-select fails when EntityGraph is specified for find operation

Description

IllegalArgumentException is thrown during two phase load's plan creation for member relation (i.e. ManyToMany).

While resolving relation, MetamodelGraphWalker visits each attribute of target entity type and checks whether fetchgraph or loadgraph has directed to eagerly fetch that attribute. If so, it modifies load plan.

Recent changes in 5.4.0 uses contracts specified by JPA 2.0 to walk down and manage types. getAttribute(name) contract specified by JPA's ManagedType throws IllegalArgumentException when asked attribute named as 'name' is not found.

But as per Hibernate's implementation, this contract is being used to check and modify load plan if attribute matches with specified EntityGraph.

In attached test case,
1) Defect class is loaded with fetch graph to load comments as well.
2) Hibernate successfully fires left join query on both tables and Result set is transformed to Entities
3) During initialization, Hibernate encounters User type in path
4) Hibernate start generating load plan for User type using internalLoad and encounter that entitygraph (specified for 'Defect' Type) is defined for this query
5) "User" type is walked down by MetamodelWalker to figure out matching fields with EntityGraph
6) No match is found (obviously because EntityGraph specified was written for "Defect" type, not "User" type)
7) Recent changes marks this situation as exceptional.

Environment

None

Activity

Show:
Steve Ebersole
December 31, 2018, 1:51 AM

I have verified this is a regression. It only occurs in #find operations, however; querying with the graph works perfectly fine as a workaround.

I am not convinced the regression is actually related to the entity-graph changes . It seems to be related instead to a change in how associations are loaded via "subsequent select" (non-joined eager load). E.g., the test tries to load a Defect and its comments eagerly (via graph). Those comments specify that both the associated Defect and User ought to be eagerly loaded. The Defect is already loaded via the main #find; the User however needs to be loaded.

In 5.3 and earlier the User load is triggered after the initial #find completes. In 5.4 it is triggered during the #find. It is a significant difference. In the finally block of #find the graphs are cleared from the LoadQueryInfluencers associated with the Session. So in 5.3 we have (roughly):

However, in 5.4 we have:

Any idea what changed in 5.4 that changed that behavior?

Harsh Panchal
December 31, 2018, 8:10 PM

,
I have checked in all versions till 4.3, #internalLoad is called within #find to load User. So i don't think LoadQueryInfluencer#setGraph(null) was ever effective. In my observation, all calls to load User operation was influenced by entity graph.

Steve Ebersole
January 1, 2019, 1:52 AM

Not sure what you mean about LoadQueryInfluencer#setGraph(null) not ever being effective. LoadQueryInfluencer#setGraph(null) was not called before, which is my point.

As for #internalLoad called during or after #find... it seemed to happen both ways in my testing and I was never able to determine the distinction. And honestly the reason is not relevant as allowing for "get attribute or null by name" semantics on our ManagedType descriptor is a simple solution mimicking what happened pre-5.4 (though still with the perf improvement)

Fixed

Assignee

Steve Ebersole

Reporter

Harsh Panchal

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

backportDecision

None

Worked in

5.3.7

Components

Affects versions

Priority

Major