I have an entity with a @ManyToOne
relation, which I'd like to retrieve with a single query, thus using @Fetch(FetchMode.JOIN)
. Sometimes Hibernate doesn't respect that and issues N+1 SELECT
s. With sometimes I mean that since I don't know what triggers it, I have cases which on the same class for different queries this could happen or not.
This is a simplified entity with the annotations I use:
@Entity
public class Employee {
@ManyToOne
@Fetch(FetchMode.JOIN)
private Department department;
}
With
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);
Root<Employee> root = criteriqQuery.from(Employee.class);
TypedQuery<Employee> typedQuery = entityManager.createQuery(criteriaQuery);
List<Employee> employees = typedQuery.getResultList();
I would expect a single query to fetch both Employee
and its Department
, something like
select ... from Employee join Department on ...
instead I get a first select for all N Employee
s and then N SELECT
s for all Department
s (consider no cache).
I've found many similar questions, but their answers suggest workarounds and do not explain why this is happening. Please, avoid answers suggesting to use lazy loading: it's not what I'm asking.
In general, FetchMode defines how Hibernate will fetch the data (by select, join or subselect). FetchType, on the other hand, defines whether Hibernate will load data eagerly or lazily.
Hibernate defines the following fetching strategies: Join fetching: Hibernate retrieves the associated instance or collection in the same SELECT , using an OUTER JOIN . Select fetching: a second SELECT is used to retrieve the associated entity or collection.
The FETCH keyword of the JOIN FETCH statement is JPA-specific. It tells the persistence provider to not only join the 2 database tables within the query but to also initialize the association on the returned entity. You can use it with a JOIN and a LEFT JOIN statement.
The rule is quite simple: Queries ignore fetch modes. When you write a query, you are telling what is joined and what is not joined.
Fetch mode is only taken into account when entity is loaded with methods like EntityManager.find(class, id)
or when navigating through some other entity graph and loading its associations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With