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

JPA中父子表均含复合主键的一对多关联实现方案问询

针对你给出的数据库表结构和JPA实体定义需求,我整理了完整的实现方案,包括数据库表细节和对应的JPA实体代码:

数据库表结构定义

父表 FATHER_TABLE

  • 复合主键:CONF_ID + CONF_TYPE
  • 核心字段详情:
    • CONF_ID:NUMBER(2) 类型
    • CONF_TYPE:VARCHAR2(10) 类型
    • 其他无关字段略

子表 CHILD_TABLE

  • 复合主键:CONF_ID + CONF_TYPE + CONF_DETAIL
  • 核心字段详情:
    • CONF_ID:NUMBER(2) 类型
    • CONF_TYPE:VARCHAR2(10) 类型
    • CONF_DETAIL:NUMBER(2) 类型
    • 其他无关字段略
JPA实体实现

父表复合主键类 FatherId

这是实现Serializable的主键类,用于映射父表的复合主键(JPA要求复合主键类必须实现序列化,并重写equals和hashCode):

public class FatherId implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private Long confId;
    private String confType;

    // JPA要求必须提供无参构造函数
    public FatherId() {}

    // 带参构造函数,方便快速创建主键实例
    public FatherId(Long confId, String confType) {
        this.confId = confId;
        this.confType = confType;
    }

    // Getter 和 Setter 方法
    public Long getConfId() { return confId; }
    public void setConfId(Long confId) { this.confId = confId; }
    public String getConfType() { return confType; }
    public void setConfType(String confType) { this.confType = confType; }

    // 重写equals和hashCode,用于JPA主键的唯一性判断
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        FatherId fatherId = (FatherId) o;
        return Objects.equals(confId, fatherId.confId) &&
               Objects.equals(confType, fatherId.confType);
    }

    @Override
    public int hashCode() {
        return Objects.hash(confId, confType);
    }
}

父表实体类 FatherTable

使用@IdClass注解指定复合主键类,完成父表的映射:

@Entity
@Table(name = "FATHER_TABLE")
@IdClass(FatherId.class)
public class FatherTable {
    @Id
    @Column(name = "CONF_ID", precision = 2)
    private Long confId;

    @Id
    @Column(name = "CONF_TYPE", length = 10)
    private String confType;

    // 可选:与子表建立一对多关联,根据业务需求添加
    @OneToMany(mappedBy = "fatherTable", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<ChildTable> childTables = new ArrayList<>();

    // 其他无关字段的映射示例
    // @Column(name = "DESCRIPTION")
    // private String description;

    // JPA要求的无参构造函数
    public FatherTable() {}

    // Getter 和 Setter 方法
    public Long getConfId() { return confId; }
    public void setConfId(Long confId) { this.confId = confId; }
    public String getConfType() { return confType; }
    public void setConfType(String confType) { this.confType = confType; }

    public List<ChildTable> getChildTables() { return childTables; }
    public void setChildTables(List<ChildTable> childTables) { this.childTables = childTables; }

    // 便利方法:维护父子表关联关系
    public void addChildTable(ChildTable child) {
        childTables.add(child);
        child.setFatherTable(this);
    }

    public void removeChildTable(ChildTable child) {
        childTables.remove(child);
        child.setFatherTable(null);
    }
}

子表复合主键类 ChildId

子表的复合主键包含父表的主键和自身的CONF_DETAIL,同样需要实现Serializable:

public class ChildId implements Serializable {
    private static final long serialVersionUID = 1L;
    
    // 关联父表的复合主键作为子表主键的一部分
    private FatherId fatherId;
    private Long confDetail;

    public ChildId() {}

    public ChildId(FatherId fatherId, Long confDetail) {
        this.fatherId = fatherId;
        this.confDetail = confDetail;
    }

    // Getter 和 Setter 方法
    public FatherId getFatherId() { return fatherId; }
    public void setFatherId(FatherId fatherId) { this.fatherId = fatherId; }
    public Long getConfDetail() { return confDetail; }
    public void setConfDetail(Long confDetail) { this.confDetail = confDetail; }

    // 重写equals和hashCode
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ChildId childId = (ChildId) o;
        return Objects.equals(fatherId, childId.fatherId) &&
               Objects.equals(confDetail, childId.confDetail);
    }

    @Override
    public int hashCode() {
        return Objects.hash(fatherId, confDetail);
    }
}

子表实体类 ChildTable

映射子表并与父表建立多对一关联:

@Entity
@Table(name = "CHILD_TABLE")
@IdClass(ChildId.class)
public class ChildTable {
    // 关联父表,同时作为子表主键的一部分
    @Id
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "CONF_ID", referencedColumnName = "CONF_ID"),
        @JoinColumn(name = "CONF_TYPE", referencedColumnName = "CONF_TYPE")
    })
    private FatherTable fatherTable;

    @Id
    @Column(name = "CONF_DETAIL", precision = 2)
    private Long confDetail;

    // 其他无关字段的映射示例
    // @Column(name = "VALUE")
    // private String value;

    public ChildTable() {}

    // Getter 和 Setter 方法
    public FatherTable getFatherTable() { return fatherTable; }
    public void setFatherTable(FatherTable fatherTable) { this.fatherTable = fatherTable; }
    public Long getConfDetail() { return confDetail; }
    public void setConfDetail(Long confDetail) { this.confDetail = confDetail; }
}

内容的提问来源于stack exchange,提问作者Matteo Baldi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:57:56