1

I'm working on a Spring Boot 3.x application with Spring Data and Hibernate 6.x. I've got an entity class that looks like this:

@Entity
public class User {

    @Id
    private UUID id = UUID.randomUUID();

    @Column
    private String country;

    @ManyToMany(fetchType = FetchType.EAGER)
    private Set<Role> roles;

    // constructors, getters, setters, equals/hashcode based on id
}

When I do a custom query like this in a repository:

@Query("""
   FROM User user
   WHERE user.country = ?1
""")
public Set<User> getUserByCountry(String country);

... I get back a Set<User>, but their roles property is lazily loaded by Hibernate; I can clearly see that from the SQL query logging. One query for roles is sent to the DB for each user.

Now, I've been around for a while, and I clearly remember that FetchType.EAGER was frowned upon because it affected all queries and you could not opt-out of it. However, this clearly contradicts this case; lazy fetching is performed even if the roles reference is marked as EAGER. Did that behavior change in recent (major) versions of Hibernate? Can I tell Hibernate to always fetch the eager associations by default for all custom queries?

I tried using @EntityGraph to explicitly tell the custom query to fetch the roles reference eagerly. That works nicely, but I would strongly prefer hibernate to infer this information from the annotations on the entities if no @EntityGraph annotation is provided.

EDIT: I verified yesterday that the fetch behavior was in fact different with spring boot 2.x and hibernate 5.x. This appears to be a Hibernate 6.x thing.

Martin Häusler
  • 6,544
  • 8
  • 39
  • 66
  • That is interesting, I have checked and indeed there are no "expected" joins (adding `LEFT JOIN FETCH roles` make sense though). However, formally, `FetchType` does not specify what SQLs persistence provider should produce - it just defines what associations must be initialized prior client getting control over result. – Andrey B. Panfilov Jan 27 '23 at 01:10
  • @AndreyB.Panfilov I'm still not sure if this is a bug in Hibernate 6 or a feature. It's a change with massive implications and no update guide or release notes document I've found online mentions it... – Martin Häusler Jan 27 '23 at 07:52

1 Answers1

0

The generated SQL query should include a join to fetch the roles as part of your main query. It could be, that in your real model, when you have multiple of such eager collections, that Hibernate has to issue separate queries to avoid multiple bag fetches, which would alter the cardinality of the result. If you just have a single eager collection though, please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.

Christian Beikov
  • 15,141
  • 2
  • 32
  • 58