Hibernate中从无主键表获取实体的异常问题排查
解决Hibernate关联无主键表时重复获取第一条数据的问题
哥们儿,我一眼就瞅出问题出在你的复合主键配置上了——Hibernate没法正确区分dk_systemtherapie_merkmale表的不同实体,才会一直重复返回第一条数据。咱们来一步步把这个坑填上:
核心问题分析
你的DkSystemtherapieMerkmaleEntity实体类犯了两个关键错误:
- 错误使用
@IdClass:你把实体类自身作为主键类,这不符合Hibernate的规范——@IdClass需要一个单独的、仅承载主键字段的序列化类。 - 主键字段与关联字段重复映射:你同时给
eintragId和关联的dkSystemtherapieByEintragId都加了@Id注解,这直接导致Hibernate的主键识别逻辑混乱,没法区分不同的实体条目。
修复步骤
第一步:创建独立的复合主键类
先写一个专门的主键类,用来承载dk_systemtherapie_merkmale表的三个主键字段,必须实现Serializable,并重写equals和hashCode方法:
import java.io.Serializable; import java.util.Objects; public class DkSystemtherapieMerkmaleId implements Serializable { private Integer eintragId; private String feldname; private String feldwert; // 必须提供无参构造器 public DkSystemtherapieMerkmaleId() {} public DkSystemtherapieMerkmaleId(Integer eintragId, String feldname, String feldwert) { this.eintragId = eintragId; this.feldname = feldname; this.feldwert = feldwert; } // 重写equals和hashCode,让Hibernate能区分不同主键 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DkSystemtherapieMerkmaleId that = (DkSystemtherapieMerkmaleId) o; return Objects.equals(eintragId, that.eintragId) && Objects.equals(feldname, that.feldname) && Objects.equals(feldwert, that.feldwert); } @Override public int hashCode() { return Objects.hash(eintragId, feldname, feldwert); } }
第二步:修正实体类的映射配置
修改DkSystemtherapieMerkmaleEntity的注解,引用刚才创建的主键类,去掉关联字段上的@Id,并设置关联字段为不可插入/更新(因为主键字段已经映射了eintragId):
@Entity @IdClass(DkSystemtherapieMerkmaleId.class) // 引用正确的主键类 @Table(name = "dk_systemtherapie_merkmale", schema = "***", catalog = "") public class DkSystemtherapieMerkmaleEntity implements Serializable { @Id @Column(name = "eintrag_id") private Integer eintragId; @Id @Column(name = "feldname") private String feldname; @Id @Column(name = "feldwert") private String feldwert; private DkSystemtherapieEntity dkSystemtherapieByEintragId; // 主键字段的getter/setter public Integer getEintragId() { return eintragId; } public void setEintragId(Integer eintragId) { this.eintragId = eintragId; } public String getFeldname() { return feldname; } public void setFeldname(String feldname) { this.feldname = feldname; } public String getFeldwert() { return feldwert; } public void setFeldwert(String feldwert) { this.feldwert = feldwert; } // 关联字段:去掉@Id,设置insertable=false, updatable=false避免重复映射 @ManyToOne @JoinColumn(name = "eintrag_id", referencedColumnName = "id", insertable = false, updatable = false) public DkSystemtherapieEntity getDkSystemtherapieByEintragId() { return dkSystemtherapieByEintragId; } public void setDkSystemtherapieByEintragId(DkSystemtherapieEntity dkSystemtherapieByEintragId) { this.dkSystemtherapieByEintragId = dkSystemtherapieByEintragId; } }
第三步:确认主实体类的关联配置
你的DkSystemtherapieEntity的@OneToMany配置没问题,保持原样即可,现在Hibernate能通过复合主键正确识别每个关联的DkSystemtherapieMerkmaleEntity条目了。
为什么这样改?
- 独立的主键类让Hibernate能通过
equals和hashCode判断实体的唯一性,不会再把不同条目当成同一个。 - 关联字段设置
insertable=false, updatable=false,避免了eintragId字段被重复映射的问题,Hibernate会用主键字段的映射来处理这个字段的读写。
现在重新运行程序,应该就能正确获取所有关联的条目,不会再重复返回第一条数据啦!
内容的提问来源于stack exchange,提问作者Sara Klüber
相关产品推荐
相关产品推荐

