Reputation: 41
I have a Spring Boot application using Hibernate as JPA provider. My application has two entities connected with a @OneToMany
/ @ManyToOne
relation. The relation is annotated with @Fetch(FetchMode.JOIN)
on both directions, and fetch = FetchType.EAGER
.
My entities are called Car
and Driver
:
@Entity
@Table(name = "car")
@Data
public class Car implements Serializable, Cloneable {
@Id
@GenericGenerator(name = "car_seq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = {
@Parameter(name = "sequence_name", value = "car_seq") })
@GeneratedValue(generator = "car_seq")
private Integer id;
@OneToMany(mappedBy = "car", fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private List<Driver> drivers = new ArrayList<>();
@Column(name = "license_no", nullable = false)
private String licenseNo;
}
@Entity
@Table(name = "driver")
@Data
public class Driver implements Serializable, Cloneable {
@Id
@GenericGenerator(name = "driver_seq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = {
@Parameter(name = "sequence_name", value = "driver_seq") })
@GeneratedValue(generator = "driver_seq")
private Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "car_id", nullable = true)
@Fetch(FetchMode.JOIN)
private Car car;
@Column(name = "name", nullable = false)
private String name;
}
When selecting a care (e.g. by calling Car.findById()
), Hibernate joins the the two tables in a single SQL, and returns a Car
object with a list of Drivers
.
But if I select a single driver, Hibernate will join the Driver
and Car
table to give me the Driver
object with the Car
property populated, but it will run a second query to fetch all the driver objects on for the list on the car object.
For performance reasons I would like all the involved objects to be fetched in a single query, as is the case when I fetch a car. But I cannot find a way to make Hibernate do this. There is a property, hibernate.max_fetch_depth
, which is supposed to do this, but I have found that it only affects the behavior of fetching a car, not when I fetch a driver.
I know I can use an EntityGraph
to control the fetching, and by using an EntityGraph
I have successfully retrieved a driver object with its car and all the car's drivers in one query. But to do that, I have to explicitly use a graph when retrieving the object, and I cannot do that in all the various cases where a Car
object is needed. There are lots of other entities that have a relation to Car
, and I don't want to write an EntityGraph
for each and every one of those.
So is there a way to tell Hibernate how you want the fetching to be done by default on an entity? I would have thought that the annotations would be enough, but it seems that there either has to be something more, or that this simply cannot be done.
Arndt
Upvotes: 4
Views: 1018
Reputation: 2851
FetchType.EAGER
is one of the most common reasons for performance problems. You should use
@OneToMany(mappedBy = "car")
private List<Driver> drivers = new ArrayList<>();
And fetch drivers If needed
SELECT c FROM Car c JOIN FETCH c.drivers
Upvotes: 3