忽略关系中的FetchType.EAGER

Dhe*_*rik 25 java hibernate jpa hql jpql

我在大型应用程序中遇到EAGER关系问题.此应用程序中的某些实体EAGER与其他实体有关联.这在某些功能中变成了"毒药".

现在我的团队需要优化这些功能,但我们不能将获取类型更改为LAZY,因为我们需要重构整个应用程序.

所以,我的问题:是否有办法在我返回的实体中忽略EAGERs关联来执行特定查询?

示例:当我有这个实体Person时,我想在查询人员时不带地址列表.

@Entity
public class Person {

  @Column
  private String name;

  @OneToMany(fetch=FetchType.EAGER)
  private List<String> address;

}

Query query = EntityManager.createQuery("FROM Person person");
//list of person without the address list! But how???
List<Person> resultList = query.getResultList();
Run Code Online (Sandbox Code Playgroud)

谢谢!

更新

我找到的唯一方法是不返回实体,只返回实体的某些字段.但我想找到一个可以返回实体的解决方案(在我的例子中,Person实体).

我在想是否可以在Hibernate中将同一个表映射两次.通过这种方式,我可以在没有EAGER关联的情况下映射同一个表.在一些情况下,这对我有帮助......

Mil*_*lan 11

如果您使用的是JPA 2.1(Hibernate 4.3+),您可以使用@NamedEntityGraph实现您想要的效果.

基本上,您可以像这样注释您的实体:

@Entity
@NamedEntityGraph(name = "Persons.noAddress")
public class Person {

  @Column
  private String name;

  @OneToMany(fetch=FetchType.EAGER)
  private List<String> address;

}
Run Code Online (Sandbox Code Playgroud)

然后使用提示来获取没有地址的Person,如下所示:

EntityGraph graph = this.em.getEntityGraph("Persons.noAddress");

Map hints = new HashMap();
hints.put("javax.persistence.fetchgraph", graph);

return this.em.findAll(Person.class, hints);
Run Code Online (Sandbox Code Playgroud)

有关此主题的更多信息,请点击此处.

当您使用获取图时,只会急切地获取放在@NamedEntityGraph中的字段.

在没有提示的情况下执行的所有现有查询将保持不变.

  • 实际上这不起作用,即使你没有在你的EntityGraph中包含它们,Hibernate仍会获取标记为EAGER的属性,请参阅:https://hibernate.atlassian.net/browse/HHH-8776这个答案不能有已经过测试,因为它不能按预期工作. (4认同)

Dhe*_*rik 8

更新(09/06/2020):

问题已在 5.4.11 版本中解决。我现在无法测试,但预计图中未包含的 JPA 实体图属性应保持卸载状态,即使它们已声明EAGER

原答案

经过这么多年,在 Hibernate 上覆盖 EAGER 映射是不可能的。来自最新的 Hibernate 文档(5.3.10.Final):

尽管 JPA 标准规定您可以在运行时使用 javax.persistence.fetchgraph 提示覆盖 EAGER 获取关联,但目前,Hibernate 未实现此功能,因此无法延迟获取 EAGER 关联。有关更多信息,请查看 HHH-8776 Jira 问题。

在执行 JPQL 查询时,如果省略了 EAGER 关联,Hibernate 将针对需要急切获取的每个关联发出辅助选择,这可能导致 dto N+1 查询问题。

出于这个原因,最好使用 LAZY 关联,并且只在每个查询的基础上急切地获取它们。

和:

EAGER 获取策略不能在每个查询的基础上被覆盖,因此即使您不需要关联也总是会被检索。此外,如果您忘记在 JPQL 查询中 JOIN FETCH EAGER 关联,Hibernate 将使用辅助语句对其进行初始化,这反过来会导致 N+1 查询问题。