Reputation: 7749
In my project I have three Entities like this:
@Entity
public class A {
@Id
private int id;
}
@Entity
public class B {
@Id
private int id;
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private A a;
}
@Entity
public class C {
@Id
private int id;
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private B b;
}
As you can see, C
has a tansitive ManyToOne-Relationship with A
.
Now, I want to fetch all C
s with a specific A
using my JpaRepository
:
public interface CRepository extends JpaRepository<C, Integer> {
List<C> findAllByBA(A a);
}
Which results in the following Hibernate sql query (which is fine):
Hibernate: select ... from c c0_ cross join b b1_ where c0_.b_id=b1_.id and b1_.a_id=?
But afterwards I get another query for each distinct B
(which can be several thousand, so is not fine):
Hibernate: select ... from b b0_ inner join a a1_ on b0_.a_id=a1_.id where b0_.id=?
Obviously, this could be solved with a single join using all three tables. But how do I tell Hibernate to do that without losing the convenience of abstraction with JpaRepository
?
Upvotes: 0
Views: 1255
Reputation: 691635
The additional, unwanted, queries are caused by the fact that the association is eager. To avoid loading the Bs, you should make the association lazy:
@ManyToOne(fetch: FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
I generally make every association lazy. When you're not interested in Bs, or do not know in advance if loading Bs is necessary, making the association lazy avoids loaded them. And if you know you want the Bs to be loaded along with the Cs, then you just load them explicitly in your query:
@Query("select c from C c left join fetch c.b where c.b.a = ?")
Upvotes: 2