2

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);
SternK
  • 11,649
  • 22
  • 32
  • 46
J.T.
  • 129
  • 2
  • 7
  • What is your way to fetch Auto ? – antoine.lange Mar 20 '20 at 05:02
  • @J.T. What hibernate version do you use? – SternK Mar 20 '20 at 06:59
  • @J.T. and could you describe a method how you load an entity? Is it `EntityManager.find(class, id)`? – SternK Mar 20 '20 at 07:03
  • @SternK I'm using Hibernate 5.3.7 – J.T. Mar 20 '20 at 13:34
  • @antoine.lange My query is asking for Auto as a FETCH JOIN to something else... maybe that's my problem? I'll update the original post with more information. – J.T. Mar 20 '20 at 13:40
  • As Dragan said in https://stackoverflow.com/questions/36796798/why-hibernate-sometimes-ignores-fetchmode-join, if you are using Query or TypedQuery to fetch your data, the annotation @Fetch is not considered, as you control the fetch of your data – antoine.lange Mar 20 '20 at 14:33
  • @antoine.lange That is my confusion! In that post it says the Fetch is not considered, so I don't understand why using FetchMode.SUBSELECT made such a difference. What am I missing? – J.T. Mar 20 '20 at 16:03

1 Answers1

1

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).

Community
  • 1
  • 1
SternK
  • 11,649
  • 22
  • 32
  • 46
  • Thank you very much! Thank you for editing my post for readability, I like the changes. – J.T. Mar 23 '20 at 17:18