我有以下类(class):
@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 {
// ...
}
现在我基本上想加载所有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 集合。
解释为什么会发生这种情况也很好,因为我似乎无法弄明白。
最佳答案
如果您想在没有 (n+1) 个选择的情况下检索 Bar 和 Baz,请使用以下 hql。
SELECT b FROM Base b LEFT JOIN FETCH b.bars bar LEFT JOIN FETCH bar.baz
这应该只产生一个 sql。
此外,如果您不想获取“Baz”,只需将 Bar->Baz 的关联设置为“惰性”即可。
默认情况下,JPA 对“@OneToOne”和“@ManyToOne”关联实现“急切”获取。因此,您必须明确地使其惰性化,如下所示。
@Entity
public class Bar {
@OneToOne
@JoinColumn(name = "baz_id", nullable = false, fetch=FetchType.Lazy)
private Baz baz;
//...
}
关于java - 避免子集合元素关联的n+1 eager fetching,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13378656/