问题描述
我对Spring Boot / Hibernate开发还很陌生,这是我的第一个大型项目。
我有一个使用Spring Boot,Hibernate和Hibernate Envers审核某些实体的应用程序。 Hibernate Envers设置为使用ValidityAuditStrategy。 由于Hibernate Envers不支持但仍急于立即加载对许多关系,因此我试图找到一种方法来执行单个查询并检索所需的所有数据,以避免N + 1查询此刻正在破坏我的性能的问题:在我们的开发环境中,用所需的关系完全加载我们所需的实体大约需要2分钟。
由于我需要检索经过审核的版本,因此无法像在应用程序其他部分中那样使用EntityGraph(至少据我所知)。
我要解决的情况之一是有四个实体Parameter
,Formula
,Value
和Variable
,它们之间的关系是这样的(仅显示相关部分, Value
和Variable
是实体,未在此处列出)
@Entity
public class Parameter {
@OnetoOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "formula_id",referencedColumnName = "id",nullable = false)
private Formula formula;
}
@Entity
public class Formula {
@ManyToOne(optional = false)
@JoinColumn(name = "tag_id")
private Value tag;
@ManyToMany
@JoinTable(
name = "Formulas_Variables",joinColumns = @JoinColumn(name = "formula_id"),inverseJoinColumns = @JoinColumn(name = "variable_id"))
private Set<Variable> variables = new HashSet<>();
}
我试图做的是创建一个自定义查询并使用@NamednativeQuery
和@sqlresultsetmapping
映射结果,尽管Hibernate正在创建Formula
和Value
之间的关系正确地,它不是在variables
字段上创建数组。我使用的查询和映射如下:
@sqlresultsetmapping(name = "Parameter.findAllByRevisionMapping",entities = {
@EntityResult(entityClass = Parameter.class,fields = {
@FieldResult(name = "id",column = "id"),@FieldResult(name = "formula",column = "formula_id")
}),@EntityResult(entityClass = Formula.class,column = "formulaId"),@FieldResult(name = "tag",column = "tag_id"),@FieldResult(name = "variables",column = "variable_id")
}),@EntityResult(entityClass = DomainValue.class,column = "tag_id")
}),@EntityResult(entityClass = Variable.class,column = "variableId")
})
})
@NamednativeQuery(name = "Parameter.findAllByRevision",query = "SELECT om_c_p_aud.id,\n"
+ " f_aud.id AS formulaId,\n"
+ " dv_aud.id AS tag_id,\n"
+ " fv_aud.formula_id AS formula_id,\n"
+ " v_aud.id AS variable_id,\n"
+ " v_aud.id AS variableId\n"
+ "FROM Parameters_AUD om_c_p_aud\n"
+ " LEFT OUTER JOIN Formulas_AUD f_aud\n"
+ " ON f_aud.id = om_c_p_aud.formula_id AND f_aud.REV <= ?1 AND\n"
+ " f_aud.REVTYPE <> 2 AND (f_aud.REvend > ?1 OR\n"
+ " f_aud.REvend IS NULL)\n"
+ " LEFT OUTER JOIN Values_AUD dv_aud\n"
+ " ON dv_aud.id = f_aud.tag_id AND dv_aud.REV <= ?1 AND\n"
+ " dv_aud.REVTYPE <> 2 AND (dv_aud.REvend > ?1 OR\n"
+ " dv_aud.REvend IS NULL)\n"
+ " LEFT OUTER JOIN Formulas_Variables_AUD fv_aud\n"
+ " ON fv_aud.formula_id = f_aud.id AND fv_aud.REV <= ?1 AND\n"
+ " fv_aud.REVTYPE <> 2 AND (fv_aud.REvend > ?1 OR\n"
+ " fv_aud.REvend IS NULL)\n"
+ " LEFT OUTER JOIN Variables_AUD v_aud\n"
+ " ON v_aud.id = fv_aud.variable_id AND v_aud.REV <= ?1 AND\n"
+ " v_aud.REVTYPE <> 2 AND (v_aud.REvend > ?1 OR\n"
+ " v_aud.REvend IS NULL)\n"
+ "WHERE om_c_p_aud.REV <= ?1\n"
+ " AND om_c_p_aud.REVTYPE <> 2\n"
+ " AND (om_c_p_aud.REvend > ?1 OR\n"
+ " om_c_p_aud.REvend IS NULL)",resultSetMapping = "Parameter.findAllByRevisionMapping")
我在调用findAllByRevision
查询时收到的json对象的结果数组是这样的
[
{
"id":1,"formula":{
"id":52,"tag":{
"id":20
},"variables":null
}
},{
"id":2,"formula":{
"id":88,"tag":{
"id":24
},"variables":null
}
}
]
我期望的是
[
{
"id":1,"variables":[
{
"id":4
}
]
}
},"variables":[
{
"id":3
},{
"id":23
},{
"id":33
},{
"id":34
},{
"id":35
},{
"id":52
}
]
}
}
]
有人知道为什么它不创建公式变量关系吗?在类似情况下使用EntityGraph时,我尝试检查由Hibernate创建的查询,在我看来,它与上面显示的查询相同。我仍然无法检查在这种情况下使用的映射(再次理解)。
解决方法
您应该能够使用HQL为审核的关联指定联接提取。审计实体就像普通实体一样。实体名称通常后缀“ _AUD”,因此,如果要查询Parameters
的审核信息,可以查询Parameters_AUD
,例如:
SELECT p
FROM Parameters_AUD p
LEFT JOIN FETCH p.values
LEFT JOIN FETCH p.variables