Arnaud Denoyelle
Arnaud Denoyelle

Reputation: 31273

Prevent Hibernate from loading lazy ManyToOne

I reduced the problem to 3 entities in my model :

The Location class:

@Entity
@Table(name = "***")
public class Location {

   @ManyToOne
   @JoinColumn(name = "s_id")
   private Station s;

   @ManyToOne
   @JoinColumn(name = "g_id")
   private GroupOfLocations group;      

 }

And the class for GroupOfLocation :

@Entity
@Table(name = "***")
public class GroupOfLocation {

  @ManyToOne(fetch = FetchType.LAZY) //I do not want the Station to be loaded
  @JoinColumn(name = "s_id")
  private Station s;

}

When I get a Location by ID:

  1. Its Station is loaded
  2. The Location's group is loaded
  3. The Group's Station is loaded BUT I do not need it.

Problem : The group contains the station but I do not want it to be loaded. I expected that fetch = FetchType.LAZY would prevent the Station from being fully loaded but it does not work.

I have searched on SO and sometimes, the problem comes from a class declared as final but there is no final class in this model.

Any idea?

This is how the entity id searched by ID:

public Location getById(Integer id) {
  CriteriaBuilder cb = em.getCriteriaBuilder();
  CriteriaQuery<Location> query = cb.createQuery(Location.class);
  Root<Location> entity = query.from(Location.class);
  Predicate whereClause = cb.equal(entity.get(Location_.id), id);
  query.where(whereClause); 
  return em.createQuery(query).getSingleResult();
}

Upvotes: 4

Views: 3125

Answers (2)

Vlad Mihalcea
Vlad Mihalcea

Reputation: 154090

Any JPQL or Criteria query is going to override the default fetch plan (the one you defined in the entity mapping).

The default query plan is only valid when loading the entity using find or getReference

entityManager.find(GroupOfLocation.class, 1L);

The default @ManyToOne fetch is EAGER but since you haven't issued a join fetch those will be extracted with some additional selects.

The location.group.station won't be fetched with an additional select but a Proxy will still be there.

If the location.station happens to match the location.group.station then Hibernate will use the already loaded location.station, since inside a Hibernate Session object equality matches instance equality too (meaning there can only be one object of an Entity type with a given entity identifier).

So in case both location.group.station and location.station reference the same entity, you will see an initialized Proxy, otherwise the proxy will remain uninitialized.

If the session is closed and the Proxy wasn't initialized you will get a Lazy exception when accessing it.

Upvotes: 2

Puneetsri
Puneetsri

Reputation: 254

But you didn't declare fetch = FetchType.LAZY on s & group property of locations.

Upvotes: 0

Related Questions