繁体   English   中英

动态控制 @Formula 列的延迟/急切加载

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM