Reputation: 289
I have 5 entities :
@Entity
public class A {
@OneToMany(mappedBy="a", fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<B1> b1s;
@OneToMany(mappedBy="a", fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<B2> b2s;
}
@Entity
public class B1 {
@ManyToOne
@JoinColumn(name="c")
private C c;
}
@Entity
public class B2 {
@ManyToOne
@JoinColumn(name="c")
private C c;
}
@Entity
public class C {
@OneToMany(mappedBy="d", fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<D> ds;
}
@Entity
public classD {
}
So in short, A eager join two set of Entity B1 and B2, each one eager joining (implicitely) an Entity C which in turn eager join a set of Entity D.
when loading an A object, the generated query look like
select (...) from A a0
left outer join B1 b1 on a0.id=b1.aid
left outer join C c1 on b1.cid=c1.id
left outer join D d1 on c1.id=d1.cid
left outer join B2 b2 on a0.id=b2.aid
left outer join C c2 on b2.cid=c2.id
where a0.id=?
The problem is that the Set of Entity D wich are linked to c2 (C Entity loaded via B2 Entity) are not loaded in the same query, resulting in N subsequent queries for each c2 object.
I would expect Hibernate to generate another left outer join for these objects in the first query, as it already does for the first occurence of D.
I am missing something ? I use hibernate 3.6 on an Oracle DB, is it an known issue ?
Thank you for your time.
Upvotes: 2
Views: 1029
Reputation: 23562
Indeed, this seems to be a bug or an incomplete feature. I was able to reproduce it in a simpler scenario as well:
@Entity
public class A {
@OneToMany(fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
@JoinColumn
private Set<B> bs1;
@OneToMany(fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
@JoinColumn
private Set<B> bs2;
}
@Entity
public class B {
@OneToMany(fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
@JoinColumn
private Set<C> cs;
}
@Entity
public class C {
}
When loading A
by id, the following joins are generated:
from
A a0_
left outer join
B bs1x1_
on a0_.id=bs1x1_.bs1_id
left outer join
C cs2_
on bs1x1_.id=cs2_.cs_id
left outer join
B bs2x3_
on a0_.id=bs2x3_.bs2_id
So, if you really want to fetch everything in one query, you'll have to do it with HQL:
select a from A a
left join fetch a.b1s b1
left join fetch b1.c c1
left join fetch c1.ds
left join fetch a.b2s b2
left join fetch b2.c c2
left join fetch c2.ds
where a.id = ?
However, I assume that the collections being joined are really small. Because these kinds of joins produce full Cartesian product and are considered a very bad anti-pattern.
Suppose that each of the collections contains only 100 rows (A
has 100 b1s
and 100 b2s
, and each of b1s
and b2s
has a C
which has 100 ds
). Then you will get and read a result set containing 100 million rows!
But with lazy collections and batch fetching for example, you would read a total of about 400 rows in a few queries, which is much faster than reading 100 million rows in one query.
Upvotes: 2