join-fetch associated entity by default

154 Views Asked by At

My Hibernate/JPA model has this entity classes

@Entity
public class Student {

    @ManyToOne(optional = false)
    @JoinColumn(name = "course_id")
    private Course course;

    // other properties, getters, setters, etc. omitted
}

This student-course relationship is unidirectional i.e. there is no reference to the Student entity in Course.

The default fetch type for @ManyToOne is eager, so the annotation above is the same as @ManyToOne(optional = false, fetch = FetchType.EAGER).

So whenever I execute a query that fetches students, the associated courses are also fetched, e.g.

select s
from Student s
where s.name = 'Bob'

However, although the courses are fetched at the same time, a separate query is issued to fetch them. If I want to fetch the student(s) and course(s) in a single query, I need to explicitly include a join fetch in my JPQL query, e.g.

select s
from Student s
join fetch s.course
where s.name = 'Bob'

As it's tedious and error prone to apply this update to all my student queries, is it possible to make join-fetching the default behaviour? In other words, to have the first query (without an explicit join) behave like the second query (join-fetch course by default)?

2

There are 2 best solutions below

0
Per Huss On

There is no such possibility, I'm afraid. The join clause have semantics that may affect the query, so it would be dangerous to add a default clause. Consider an example like yours, but where the course relation is optional. A join fetch s.course would limit the result to students that have a course reference (it is an inner join after all), and students without courses (or with invalid course references) would simply be invisible to the query.

The JPA 3.1 specification states that

A FETCH JOIN enables the fetching of an association or element collection as a side effect of the execution of a query.

Unless you prove that there are considerable performance advantages of fetching it all in one query, I would recommend settling with the default behaviour...

6
Rajesh Mishra On
import javax.persistence.*;

@Entity
public class Student {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "course_id")
    private Course course;

}
============================================
import javax.persistence.*;
import java.util.List;

@Entity
public class Course {

    @OneToMany(mappedBy = "course", cascade = CascadeType.ALL)
    private List<Student> students;

}