J.T.
J.T.

Reputation: 129

Hibernate FetchMode.JOIN vs FetchMode.SUBSELECT

I have a @OneToMany relationship and am using Hibernate 5.3.7 to write an EAGER fetch. I realize EAGER fetching is an anti-pattern, this is a very specific use case. According to this article I can use FetchMode.JOIN in my TypedQuery and Hibernate should create a nice query for me, however, I saw it spam a few dozen select statements. It wasn't until I changed this to FetchMode.SUBSELECT that it condensed the query into one select statement. I realize this is similar to Why Hibernate sometimes ignores FetchMode.JOIN?, however, I don't understand why FetchMode.JOIN did not work since this is all within a Hibernate query. Any ideas?

Below are the annotations I'm using on the OneToMany side:

@Entity
@Table(name = "auto", schema = "us")
public class Auto extends AbstractTable {

   /** Ordered list of tires. */
   @OneToMany(mappedBy = "auto", fetch = FetchType.EAGER, orphanRemoval = true)
   @Fetch(FetchMode.SUBSELECT)
   private List<Tire> tires;
   ...
}

I am using SpringBoot with @PersistenceContext to get my EntityManager. The Auto has a bi-directional OneToOne relationship with its containing class AutoOwnerThing.

final String queryString = "FROM AutoOwnerThing e JOIN FETCH e.auto WHERE e.id in :ids";
TypedQuery<AutoOwnerThing> = entityManager.createQuery(queryString, AutoOwnerThing.class);

Upvotes: 2

Views: 4565

Answers (1)

SternK
SternK

Reputation: 13051

Actually, the Dragan's answer is not completely correct.

According to the hibernate documentation:

The reason why we are not using a JPQL query to fetch multiple Department entities is because the FetchMode.JOIN strategy would be overridden by the query fetching directive.

To fetch multiple relationships with a JPQL query, the JOIN FETCH directive must be used instead.

Therefore, FetchMode.JOIN is useful for when entities are fetched directly, via their identifier or natural-id.

Also, the FetchMode.JOIN acts as a FetchType.EAGER strategy. Even if we mark the association as FetchType.LAZY, the FetchMode.JOIN will load the association eagerly.

But, FetchMode.SUBSELECT can be applied to hql/jpql.

Imagine we have the following mapping:

@Entity
public class Department
{
   // ...

   @OneToMany(mappedBy = "department", fetch = FetchType.EAGER)
   @Fetch(FetchMode.SUBSELECT)
   private List<Employee> employees;
}

and then we run the following query:

List<Department> deps = session.createQuery(
   "select d from Department d where d.id in :ids", Department.class)
.setParameter("ids", Arrays.asList(1L, 2L)).getResultList();

The AbstractCollectionPersister.getAppropriateInitializer method will use the org.hibernate.loader.collection.SubselectOneToManyLoader(Department.employees) loader. However, without the @Fetch(FetchMode.SUBSELECT) annotation will be used the org.hibernate.loader.collection.plan.CollectionLoader(Department.employees).

Upvotes: 2

Related Questions