3

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.

Amit Bera
  • 7,075
  • 1
  • 19
  • 42
Depressio
  • 1,329
  • 2
  • 20
  • 39
  • Did you figure this out? I'm stuck someplace similar. – Jan Mar 03 '23 at 07:35
  • 'I feel like that's a hack and probably not the right solution' - well, depends on what you define as 'right'. Performance-wise it's exactly the same, since there's no way to get the parents' and children's data in a single query anyway – crizzis Jun 20 '23 at 20:15

0 Answers0