【发布时间】:2020-10-28 23:09:49
【问题描述】:
我对 Spring Boot/Hibernate 开发还很陌生,这是我的第一个大项目。
我有一个应用程序使用 Spring Boot、Hibernate 和 Hibernate Envers 来审计一些实体。 Hibernate Envers 设置为使用 ValidityAuditStrategy。 由于 Hibernate Envers 尚不支持立即加载 to-Many 关系,我试图找到一种方法来执行单个查询并检索我需要的所有数据,以避免N+1 查询问题,目前正在扼杀我的表现:在我们的开发环境中,几乎需要 2 分钟才能完全加载我们需要的具有所需关系的实体。
由于我需要检索经过审核的版本,因此我无法像在应用程序的其他部分中使用的那样利用 EntityGraph(至少在我的理解中)。
我需要解决的一种情况是有 4 个实体 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, fields = {
@FieldResult(name = "id", column = "formulaId"),
@FieldResult(name = "tag", column = "tag_id"),
@FieldResult(name = "variables", column = "variable_id")
}),
@EntityResult(entityClass = DomainValue.class, fields = {
@FieldResult(name = "id", column = "tag_id")
}),
@EntityResult(entityClass = Variable.class, fields = {
@FieldResult(name = "id", 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":2,
"formula":{
"id":88,
"tag":{
"id":24
},
"variables":null
}
},
{
"id":2,
"formula":{
"id":88,
"tag":{
"id":24
},
"variables":null
}
},
{
"id":2,
"formula":{
"id":88,
"tag":{
"id":24
},
"variables":null
}
},
{
"id":2,
"formula":{
"id":88,
"tag":{
"id":24
},
"variables":null
}
},
{
"id":2,
"formula":{
"id":88,
"tag":{
"id":24
},
"variables":null
}
}
]
而我期待的是
[
{
"id":1,
"formula":{
"id":52,
"tag":{
"id":20
},
"variables":[
{
"id":4
}
]
}
},
{
"id":2,
"formula":{
"id":88,
"tag":{
"id":24
},
"variables":[
{
"id":3
},
{
"id":23
},
{
"id":33
},
{
"id":34
},
{
"id":35
},
{
"id":52
}
]
}
}
]
有谁知道为什么不创建公式 变量关系?在使用 EntityGraph 时,我尝试检查 Hibernate 创建的查询以应对类似情况,在我看来,它与上面显示的查询相同。不过,我无法检查在这种情况下使用的映射(再次以我的理解)。
【问题讨论】:
标签: java spring-boot hibernate spring-data-jpa hibernate-envers