You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate中从无主键表获取实体的异常问题排查

解决Hibernate关联无主键表时重复获取第一条数据的问题

哥们儿,我一眼就瞅出问题出在你的复合主键配置上了——Hibernate没法正确区分dk_systemtherapie_merkmale表的不同实体,才会一直重复返回第一条数据。咱们来一步步把这个坑填上:

核心问题分析

你的DkSystemtherapieMerkmaleEntity实体类犯了两个关键错误:

  1. 错误使用@IdClass:你把实体类自身作为主键类,这不符合Hibernate的规范——@IdClass需要一个单独的、仅承载主键字段的序列化类。
  2. 主键字段与关联字段重复映射:你同时给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:47:30