Reputation: 129
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
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 theFetchMode.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 aFetchType.EAGER
strategy. Even if we mark the association asFetchType.LAZY
, theFetchMode.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