I've got an eagerly fetched one-to-many collection inside of an entity:
@OneToMany(fetch = FetchType.EAGER)
@Fetch(FetchMode.SUBSELECT)
@JoinColumns({
@JoinColumn(name="FK_COL_1", referencedColumnName="keyValue1"),
@JoinColumn(name="FK_COL_2", referencedColumnName="keyValue2"),
@JoinColumn(name="FK_COL_3", referencedColumnName="keyValue3"),
})
private List<ChildRecord> children = new ArrayList<>();
This works normally when not using ScrollableResults
: query.getResultList()
. Hibernate fetches the parent entity, then subsequently fetches all the children. I can see this when SQL printing is turned on.
However, when using ScrollableResults
:
query.setReadOnly(true)
.setFetchSize(10000)
.setCacheable(false)
.scroll(ScrollMode.FORWARD_ONLY)
... it's not eagerly fetched. As a result, we reference the collection by calling the getter after the session is closed, and we get our lovely error: failed to lazily initialize a collection of role: com.foo.bar.Parent.children, could not initialize proxy - no Session
. Obviously we could just manually invoke the getter before closing the results, but I feel like that's a hack and probably not the right solution.
And so I ask: why is it not eagerly fetching the collection when using ScrollableResults
?
I debugged Hibernate a bit and discovered that the loadCounter
is set to 1 when context.initializeNonLazyCollections
is invoked (which is supposed to load the children). Because it's not zero, it doesn't initialize any of them. When using ScrollableResults
, manipulation of loadCounter
is done inside of ScrollableResultsImpl.prepareCurrentRow
via the beforeLoad()
and afterLoad()
methods. However, within Loader.loadSingleRow
(which ScrollableResultsImpl
calls), there is no afterLoad()
called before initializeNonLazyCollections()
is called on the context. Thus, loadCounter
is still stuck at 1, and none of the collections are loaded.
This is as opposed to the non-scrollable case where Loader.doQueryAndInitializeNonLazyCollections
does call afterLoad()
prior to calling initializeNonLazyCollections()
. This sets loadCounter
back to zero, and thus it can loop over the children and fetch them.
Is this a bug in Hibernate? Am I missing something here? This worked fine in Hibernate 4.3.11, but appears to not work in 5.4.24 and 5.6.8. It seems like this change is the one that broke it; using a version prior seems to resolve this particular problem, as does invoke the getters manually before closing the session.
Note: A open ticket (HHH-14383) is already open with hibernate regarding the issue.