2016-08-04 95 views
2

我们有几个实体,其中有一些使用Hibernate的@Formula批注注释的属性。注释中的SQL片段主要运行标量子查询(例如COUNT查询)。举例来说,我们有一个四层深的一对多关系层次结构:A <- B <- C <- D(其中<-表示一对多关联)。在获取类型为A的实体时,我们很想知道D类型的关联实体的数量。为此,我们在A中使用@Formula-annated财产。因为我们并不需要每次都使用这些值,所以我们宣布@Formula属性为延迟加载(我们启用了Hibernate的字节码增强功能以​​使其成为可能)。但对于某些查询,我们希望加载这些属性。我们经常在一个查询中加载数百个A类型的实体,并且动态地控制这些属性的加载/延迟加载在性能方面非常重要。我们已经使用JPA的实体图来控制哪些属性被热切地加载某些查询,但实体图似乎不适用于此。即使我们在实体图中列出了@Formula属性,它们仍然会延迟加载。动态地控制@Formula列的惰性加载/动态加载

是否可以根据每个查询基础动态地控制惰性/热切加载@Formula列?我们目前仅限于JPA Criteria Query API,并且命名查询在这里不可能。

更新:

有问题的属性不是关联到其他实体,但只是一些计算值。这意味着例如获取配置文件在这里不适用,因为它们只适用于实体关联(或者至少这是我理解Hibernate manual的方式)。这是我们的@Formula性能的一个示例:

@Entity 
public class A { 

    @Basic(fetch = FetchType.LAZY) 
    @Formula("(select count(*) from entity_D_table where ...)") 
    private int associatedDCount; 

    ... 
} 

回答

0

你可以尝试看看Hibernate的获取配置文件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 {... 

并激活查询时加盟模式,就像这样:

session=getSession(); 
session.beginTransaction(); 
//enable fetch profile for EAGER fetching 
session.enableFetchProfile("country_states"); 

正如http://www.concretepage.com/hibernate/fetchprofile_hibernate_annotation

+0

但是不是只适用于实体关联的抓取配置文件?我添加了一个代码示例,说明我们的属性是什么样子的,我不认为抓取配置文件可以在这里工作。 –

+0

你说得对。你能否考虑在你的数据库中定义一个SQL视图并在其上映射一个新的实体以便作为一个简单的属性热切地获取公式? –

+0

我一直在考虑创建一个视图,但这需要在代码库中进行很多更改。目前我们使用JPA实体图来一次性加载来自十几个表的数据,代码期望它能够获得整个实体图。但如果目前的方法在基准测试中结果太慢,我们将不得不再次考虑这一点。 –

1

您可以使用所示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)); 

这样,select查询将只包含您要求的字段,无论是映射EAGER还是LAZY。

+0

我们不使用Hibernate的Criteria API,但我猜这也可以通过JPA Criteria Query API实现。这需要在我们当前的代码库中进行相当多的修改,但是如果当前的实现被认为是缓慢的,那么这可能是值得的。并非真正解决眼前的问题,而是在任何情况下为这个想法+1。 –

+0

从我使用DTO代替实体的经验来看,当我只需要显示数据时,性能会更好:您可以控制连接数量或列数,并且可以创建特定索引来加速查询甚至更多 – jpprade

+0

那么,连接数量可以通过JPA实体图来控制,我的理解是提取太多列不应该是性能问题。但是,使用像你所描述的DTOs可以实现更多的控制和微调。但至少在我们的情况下,它也需要更多的实现工作并增加代码的复杂性,我不知道这是否是一个好的折衷。 –