忽略 FetchType.EAGER 在关系中

2022-09-01 07:49:47

我在大型应用程序中对EAGERs的关系有问题。此应用程序中的某些实体与其他实体有关联。这在某些功能中成为“毒药”。EAGER

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

那么,我的问题是:有没有办法执行特定的查询,忽略我返回的实体中的EAGERs关联?

示例:当一个我有这个实体的人,我想不带地址列表,当我做一个查询来查找一个人。

@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();

谢谢!

更新

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

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


答案 1

如果您使用的是 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;

}

然后使用提示来获取没有地址的 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);

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

当您使用提取图表时,只有您放入@NamedEntityGraph的字段才会被紧急提取。

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


答案 2

更新 (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查询中的GETING关联,Hibernate将使用辅助语句对其进行初始化,这反过来可能导致N + 1查询问题。


推荐