一尘不染

避免n + 1渴望获取子集合元素关联

hibernate

我有以下课程:

@Entity
@Table(name = "base")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING)
@ForceDiscriminator
public class Base {
    // ...
}

@Entity
@DiscriminatorValue("foo")
public class Foo extends Base {
    @OneToMany( mappedBy = "foo", cascade=CascadeType.ALL )
    private List<Bar> bars = new ArrayList<Bar>();

    // ...
}

@Entity
public class Bar {
    @ManyToOne (optional = false)
    @JoinColumn(name = "foo_id" )
    private Foo foo;

    @OneToOne
    @JoinColumn(name = "baz_id", nullable = false)
    private Baz baz;

    //...
}

@Entity
public class Baz {
    // ...
}

现在,我基本上想加载all Base,但在适用时渴望加载条,所以我使用以下查询:

SELECT b FROM Base b LEFT JOIN FETCH b.bars

在这种情况下,似乎为Bar实体产生了SELECT N + 1问题:

Hibernate: /* SELECT b FROM Base b LEFT JOIN FETCH b.bars */ SELECT ...
Hibernate: /* load com.company.domain.Baz */ SELECT ...
Hibernate: /* load com.company.domain.Baz */ SELECT ...

是否可以告诉hibernate急切地为子集合中的每个元素加载一个关联,而无需诉诸N + 1 SELECT?

我尝试了以下查询,但由于它是一个集合,因此显然无法正常工作:

SELECT b FROM Base b LEFT JOIN FETCH b.bars LEFT JOIN FETCH b.bars.baz
//Results in: illegal attempt to dereference collection [Foo.id.bars] with element property reference [baz]

我也尝试使用IN(b.bars) bars,虽然这使我可以引用子集合,但似乎并没有急于加载bars集合,这是我的目标。

解释为什么会发生这种情况也很好,因为我似乎无法弄清楚。


阅读 306

收藏
2020-06-20

共1个答案

一尘不染

如果您想不选择(n + 1)来检索Bar and Baz,请使用以下hql。

SELECT b FROM Base b LEFT JOIN FETCH b.bars bar LEFT JOIN FETCH bar.baz

这应该只导致一个sql。

另外,如果您不想获取’Baz’,则只需从Bar-> Baz’lazy’中进行关联即可。

默认情况下,JPA对“ @OneToOne”和“ @ManyToOne”关联强制执行“紧急”获取。因此,您必须显式使其变得懒惰,如下所示。

@Entity
public class Bar {

    @OneToOne
    @JoinColumn(name = "baz_id", nullable = false, fetch=FetchType.Lazy)
    private Baz baz;

    //...
}
2020-06-20