[英]Controlling lazy/eager loading of @Formula columns dynamically
我们有一些实体,它们有一堆用 Hibernate 的@Formula
注释注释的属性。 注释中的 SQL 片段主要运行标量子查询(例如COUNT
查询)。 例如,我们有一个有四个层次的一对多关系层次结构: A <- B <- C <- D
(其中<-
表示一对多关联)。 通常在获取A
类型的实体时,我们想知道D
类型的关联实体的数量。 为此,我们在A
中使用@Formula
-annotated 属性。
因为我们不需要每次都需要这些值,所以我们将@Formula
属性声明为延迟加载(我们启用了 Hibernate 的字节码增强功能来实现这一点)。 但是对于某些查询,我们希望急切地加载这些属性。 我们经常在一个查询中加载数百个A
类型的实体,动态控制这些属性的急切/延迟加载在性能方面很重要。 我们已经使用 JPA 的实体图来控制为某些查询急切加载哪些属性,但实体图似乎在这里不起作用。 即使我们在实体图中列出了@Formula
属性,它们仍然是延迟加载的。
是否可以在每个查询的基础上动态控制@Formula
列的延迟/急切加载? 我们目前仅限于 JPA Criteria Query API,并且命名查询在这里是不可能的。
更新:
有问题的属性不是与其他实体的关联,而只是一些计算值。 这意味着例如获取配置文件在这里不适用,因为它们仅适用于实体关联(或者至少我是这样理解Hibernate 手册的)。 这是我们的@Formula
属性之一的示例:
@Entity
public class A {
@Basic(fetch = FetchType.LAZY)
@Formula("(select count(*) from entity_D_table where ...)")
private int associatedDCount;
...
}
您可以使用 Critria api 使其返回 DTO 而不是实体。
在您的条件查询中,使用 Projection 仅选择您需要的列。
ProjectionList properties = Projections.projectionList();
properties.add(Projections.property("id").as("id"));
properties.add(Projections.property("name").as("name"));
properties.add(Projections.property("lazyField").as("lazyField"));
criteria.setProjection(properties);
criteria.setResultTransformer(new AliasToBeanResultTransformer(MyEntityDTO.class));
这样,无论映射 EAGER 还是 LAZY,选择查询将只包含您询问的字段。
您可以尝试查看 Hibernate 的 fetch 配置文件https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch20.html#performance-fetching-profiles 。
例如,您可以注释这样的实体
@Entity
@FetchProfile(name = "country_states", fetchOverrides = {
@FetchProfile.FetchOverride(entity = Country.class, association = "states", mode = FetchMode.JOIN)
})
public class Country implements Serializable {...
并在查询时激活 JOIN 模式,如下所示:
session=getSession();
session.beginTransaction();
//enable fetch profile for EAGER fetching
session.enableFetchProfile("country_states");
如图http://www.concretepage.com/hibernate/fetchprofile_hibernate_annotation
事实证明,在不必求助于字节码检测的情况下实现这一点并不难。
创建一个映射到同一张表的“公式”实体:
@Entity
@Table("A")
public class ACounts {
@Id
private Long id;
@Formula("(select count(*) from entity_D_table where ...)")
private int dCount;
public int getDCount() {
return dCount;
}
}
然后在您的父实体A
中,使用@ManyToOne
地关联到这个“公式”实体:
@Entity
public class A {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id", nullable = false, insertable = false, updatable = false)
private ACounts counts;
public ACounts getCounts() {
return counts;
}
...
}
现在计数查询只会在请求计数时发出(即它是惰性的!):
A a = ...
// lazily invoke count query now:
a.getCounts().getDCount()
参考: https ://stackoverflow.com/a/55581854/225217
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.