我正在使用带有Hibernate Core 5.3.9.Final的Spring Boot 2.1.4(以及Lombok,您可能会知道)。我有一个包含两个不同连接的实体:一个在单个字段上,另一个在多个字段上。我正在使用NamedEntityGraph来防止Hibernate N + 1问题,但是尽管我竭尽全力,Hibernate仍会为第二个联接生成额外的查询。
这是我的父实体:
@Entity
@Table(name = "PROC_STAT", uniqueConstraints = {@UniqueConstraint(columnNames = {"PROC_ID",
"STAT_CDE", "STAT_VAR_VAL_TXT","PRVD_KEY_VAL_TXT","DTSET_NME"})})
@IdClass(ProcessStatId.class)
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@NamedEntityGraph(name = "proc-stat",
attributeNodes = {
@NamedAttributeNode(value = "statType", subgraph = "stat-category"),
@NamedAttributeNode(value = "statVariantValue")
},
subgraphs = {
@NamedSubgraph(name = "stat-category",
attributeNodes = {
@NamedAttributeNode(value = "statCategory")})
})
public class ProcessStat extends StatsBookkeeping {
@Id
@Column(name = "PROC_ID")
private Long processId;
@Id
@Column(name = "STAT_CDE")
private Integer statId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "STAT_CDE", nullable = false, updatable = false, insertable = false)
@Fetch(FetchMode.JOIN)
private StatType statType;
@Id
@Column(name = "STAT_VAR_VAL_TXT")
private String statVariant;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({@JoinColumn(name = "STAT_CDE", updatable = false, insertable = false),
@JoinColumn(name = "STAT_VAR_VAL_TXT", updatable = false, insertable = false)})
@NotFound(action = NotFoundAction.IGNORE)
private StatVariantValue statVariantValue;
@Id
@Column(name = "PRVD_KEY_VAL_TXT")
private String providerKey;
@Id
@Column(name = "DTSET_NME")
private String datasetName;
@Column(name = "PROC_STAT_CNT")
private Integer count;
}
这是有问题的子实体:
@Entity
@Table(name = "STAT_VAR_VAL", uniqueConstraints = {@UniqueConstraint(columnNames = {"STAT_CDE","STAT_VAR_VAL_TXT"})})
@IdClass(StatVariantValueId.class)
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class StatVariantValue extends StatsBookkeeping {
@Id
@Column(name = "STAT_CDE")
private Integer statId;
@Id
@Column(name = "STAT_VAR_VAL_TXT")
private String statVariant;
@Column(name = "STAT_VAR_VAL_DSC")
private String statVariantDescription;
@Column(name = "SEQ_NUM")
private Integer sequenceNumber;
}
(我已经省略了两个实体的ID类;它们仅通过@NoArgsConstructor和@EqualsAndHashCode使用它们各自的@Id字段进行定义。StatsBookkeeping类也已被省略,仅包含审核字段)
如前所述,在“ STAT_CDE”字段上使用“ StatType”进行联接就可以了。使用EntityGraph时没有多余的查询。但是与“ StatVariantValue”的联接总是会产生额外的查询。
这里最棘手的部分是,此联接位于多个字段上,是可选的,并且可能不会填充父记录(STAT_VAR_VAL_TXT)中的字段之一;但是,在Oracle数据库中,它将表示为空白值(“”)。由于STAT_VAR_VAL表中永远不会有一个带有空白STAT_VAR_VAL_TXT值的记录,因此这些记录将永远不会联接(完全可以)。
我正在尝试通过PROC_ID字段查询父表以返回许多行。我尝试使用自动生成的JPA存储库方法(findByProcessId)以及使用@Query w / JPQL(尽管不是本地的)指定我自己的方法-结果相同。
Hibernate始终会生成一个完美的查询,该查询实际上返回我需要的所有内容(其他字段已从粘贴中删除):
Hibernate:
[...]
statvarian1_.crat_tsp as crat_tsp3_9_1_,
statvarian1_.crat_user_id as crat_user_id4_9_1_,
statvarian1_.upd_tsp as upd_tsp5_9_1_,
statvarian1_.upd_user_id as upd_user_id6_9_1_,
statvarian1_.seq_num as seq_num7_9_1_,
statvarian1_.stat_var_val_dsc as stat_var_val_dsc8_9_1_,
[...]
from stats.proc_stat processsta0_
left outer join stats.stat_var_val statvarian1_ on processsta0_.stat_cde=statvarian1_.stat_cde and processsta0_.stat_var_val_txt=statvarian1_.stat_var_val_txt
left outer join stats.stat_typ stattype2_ on processsta0_.stat_cde=stattype2_.stat_cde
left outer join stats.stat_cat statcatego3_ on stattype2_.stat_cat_cde=statcatego3_.stat_cat_cde
where processsta0_.proc_id=?
但是随后变得嘈杂并产生很多这样的声音:
Hibernate: select statvarian0_.stat_cde as stat_cde1_9_0_,
statvarian0_.stat_var_val_txt as stat_var_val_txt2_9_0_,
statvarian0_.crat_tsp as crat_tsp3_9_0_,
statvarian0_.crat_user_id as crat_user_id4_9_0_,
statvarian0_.upd_tsp as upd_tsp5_9_0_,
statvarian0_.upd_user_id as upd_user_id6_9_0_,
statvarian0_.seq_num as seq_num7_9_0_,
statvarian0_.stat_var_val_dsc as stat_var_val_dsc8_9_0_
from stats.stat_var_val statvarian0_
where statvarian0_.stat_cde=? and statvarian0_.stat_var_val_txt=?
我是Java的新手,我在这里尝试了所有我能想到的事情:将ID类移入然后移出其父实体(然后将StatVariantValueId作为SubGraph包括在内)-考虑到ID类可能导致了额外的查询,但这没有任何改变。我也尝试添加:
@Where(clause = "STAT_VAR_VAL_TXT <> ' '")
添加到ProcessStat中的@ManyToOne联接,但这也不会改变查询。
我很困惑。关于如何防止多余查询的任何想法?