Search code examples
hibernatejpaspring-data-jpaeager-loading

Force lazy loading of usually eager attributes


How do I force a specific query to lazy load an attribute, that usually has eager loading? EntityGraphType.FETCH isn't working.

@NamedEntityGraph(name="negGraphName",attributeNodes={
      @NamedAttributeNode("name"),
      @NamedAttributeNode("grup")})
class User{
  private String name;  

  @ManyToOne
  private UserGroup grup;

  @ManyToMany(fetch=FetchType.EAGER)
  protected Set<Authority> authoritiesList;
}

interface UserRepository extends CrudRepository<String, User>{
  @EntityGraph(value="negGraphName", type=EntityGraphType.FETCH)
  @Query("<custom query here>")
  private Collection<User> getUsersInSpecialQuery(@Param("paramName") String paramName);
}

basically, when I call userRepository.getUsersInSpecialQuery() the initial query joins in object, and doesn't join in authority, however then Hibernate anyway initializes the authorities list with A SEPARATE SQL QUERY PER USER RESULT, which is highly inefficient. Also, it initializes DomainObject object graph parent which is not even marked as Eager.

Disabling fetch=FetchType.EAGER on authorityList disabled the additional per-user queries, but I still want it eagerly fetched for all other queries.

EntityGraphType.Fetch's javadoc says:

When the javax.persistence.fetchgraph property is used to specify an entity graph, attributes that are specified by attribute nodes of the entity graph are treated as FetchType.EAGER and attributes that are not specified are treated as FetchType.LAZY

however clearly this is not the case for me


Hibernate : Force lazy-loadding on eager field <-- Doesn't have a solution

Fetch Type LAZY still causes Eager loading Hibernate Spring data <-- claims the problem is that the lazy attribute was loaded by viewing, however in my case, I stepped through in hibernate, and it was during materialization of the User object


Solution

  • You cant make an EAGER assosciation LAZY. I suggest you make it LAZY and in all queries where you want it EAGERly JOIN FETCH the authoritiesList so they are effectively EAGER then.

    Another option is a subentity which is basically the same as your current user entity, mapped to the same DB table but without the relationship you dont want:

    @Entity
    @Table(name="SAME_TABLE_AS_USER_ENTITY")
    class BasicUser{
      private String name;  
    
      @ManyToOne
      private UserGroup grup;
    
    }
    

    Another option would be inheritance.