Hibernate:如何将外键映射到复合主键的一部分
在Hibernate中实现外键映射到复合主键的一部分
没问题,我帮你梳理下这个场景的实现步骤,其实只要处理好实体类的注解配置就很清晰了:
1. 先定义TABLE_A的复合主键类
因为TABLE_A的主键是COMPANY_ID和SERVICE_ID组成的复合主键,我们需要先创建一个可嵌入的主键类(用@Embeddable注解),这是Hibernate处理复合主键的标准方式之一:
import jakarta.persistence.Embeddable; import java.util.Objects; @Embeddable public class TableAPK implements Serializable { // 对应TABLE_A的COMPANY_ID private String companyId; // 对应TABLE_A的SERVICE_ID private String serviceId; // Hibernate要求主键类必须有无参构造函数 public TableAPK() {} // 方便创建实例的带参构造函数 public TableAPK(String companyId, String serviceId) { this.companyId = companyId; this.serviceId = serviceId; } // 必须重写equals和hashCode,Hibernate用来判断主键是否唯一 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TableAPK tableAPK = (TableAPK) o; return Objects.equals(companyId, tableAPK.companyId) && Objects.equals(serviceId, tableAPK.serviceId); } @Override public int hashCode() { return Objects.hash(companyId, serviceId); } // getter和setter方法 public String getCompanyId() { return companyId; } public void setCompanyId(String companyId) { this.companyId = companyId; } public String getServiceId() { return serviceId; } public void setServiceId(String serviceId) { this.serviceId = serviceId; } }
2. 定义TABLE_A的实体类
接下来创建TABLE_A对应的实体类,用@EmbeddedId注解嵌入刚才定义的复合主键类:
import jakarta.persistence.*; @Entity @Table(name = "TABLE_A") public class TableA { @EmbeddedId private TableAPK id; // 这里添加TABLE_A的其他列,比如: private String otherColumn; // 无参构造函数 public TableA() {} // 带主键的构造函数 public TableA(TableAPK id) { this.id = id; } // getter和setter方法 public TableAPK getId() { return id; } public void setId(TableAPK id) { this.id = id; } public String getOtherColumn() { return otherColumn; } public void setOtherColumn(String otherColumn) { this.otherColumn = otherColumn; } }
3. 定义TABLE_B的实体类(核心部分)
TABLE_B需要把外键关联到TABLE_A复合主键中的COMPANY_ID,这里我们可以通过@ManyToOne结合@JoinColumn来实现,同时可以选择单独维护COMPANY_ID字段方便直接操作:
import jakarta.persistence.*; @Entity @Table(name = "TABLE_B") public class TableB { @Id @Column(name = "ID") private Long id; // 关联TABLE_A的COMPANY_ID字段 @ManyToOne @JoinColumn( name = "COMPANY_ID", referencedColumnName = "COMPANY_ID", // 指定关联TABLE_A复合主键中的COMPANY_ID insertable = false, updatable = false ) private TableA tableA; // 单独维护COMPANY_ID字段,方便直接赋值/查询,避免每次都要通过tableA实例获取 @Column(name = "COMPANY_ID") private String companyId; // TABLE_B的其他列 private String otherColumnB; // 无参构造函数 public TableB() {} // getter和setter方法 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public TableA getTableA() { return tableA; } public void setTableA(TableA tableA) { this.tableA = tableA; } public String getCompanyId() { return companyId; } public void setCompanyId(String companyId) { this.companyId = companyId; } public String getOtherColumnB() { return otherColumnB; } public void setOtherColumnB(String otherColumnB) { this.otherColumnB = otherColumnB; } }
关键细节说明
- 关于
insertable和updatable:因为我们已经单独维护了companyId字段,所以把这两个属性设为false,避免Hibernate在插入或更新TableB时重复操作COMPANY_ID字段。如果不想单独维护这个字段,也可以删掉它,直接通过tableA.getId().getCompanyId()来获取,但插入TableB时需要先关联一个有效的TableA实例。 - 复合主键的要求:复合主键类必须实现
Serializable接口,并且重写equals和hashCode方法,这是Hibernate识别主键唯一性的必要条件。
内容的提问来源于stack exchange,提问作者ahmad Shekha
相关产品推荐
相关产品推荐

