hibernate生成查询而不需要所有外连接提取

时间:2015-08-25 13:16:27

标签: java hibernate join

我有5个实体:

@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 {

}

总之, 热切加入两组实体B1和B2,每一组都渴望加入(隐含地)实体C,实体C又渴望加入一组实体D.

加载A对象时,生成的查询看起来像

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=?

问题在于,链接到c2的实体集D(通过B2实体加载的C实体)未加载到同一查询中,导致每个c2对象的N个后续查询。

我希望Hibernate在第一个查询中为这些对象生成另一个左外连接,因为它已经为D的第一次出现。

我错过了什么?我在Oracle DB上使用hibernate 3.6,这是一个已知的问题吗?

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

实际上,这似乎是一个错误或不完整的功能。我能够在更简单的场景中重现它:

@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 {

}

按ID加载A时,会生成以下联接:

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 

所以,如果你真的想在一个查询中获取所有内容,你必须使用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 = ?

但是,我认为加入的集合非常小。因为这些类型的连接产生 完整 笛卡尔积,并被认为是一种非常糟糕的反模式。

假设每个集合只包含100行(A有100 b1s和100 b2sb1sb2s中的每一行都有C有100 ds)。然后,您将获得并读取包含1亿行的结果集!

但是,例如,使用延迟集合和批量提取,您将在一些查询中读取总共约400行,这比在一个查询中读取1亿行要快得多。