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
相关产品推荐
相关产品推荐

