Hibernate中如何配置Delivery表的复合主键?
解决JPA复合主键(deliveryId + invoice_invoiceId)的配置问题
我来帮你搞定这个Hibernate/JPA的复合主键配置问题~你之前的代码报错,核心原因是重复的@Id注解导致主键映射混乱,而且Invoice实体的主键配置逻辑也不对。下面是完整的正确配置方案:
第一步:创建复合主键类(@Embeddable)
因为Delivery表的主键是deliveryId + invoice_invoiceId的复合键,咱们需要先定义一个可嵌入的主键类,JPA要求这类必须实现equals()和hashCode()方法:
import jakarta.persistence.Embeddable; import java.io.Serializable; import java.util.Objects; @Embeddable public class DeliveryId implements Serializable { private int deliveryId; private int invoiceInvoiceId; // 对应数据库的invoice_invoiceId字段 // JPA要求必须有无参构造函数 public DeliveryId() {} public DeliveryId(int deliveryId, int invoiceInvoiceId) { this.deliveryId = deliveryId; this.invoiceInvoiceId = invoiceInvoiceId; } // 重写equals和hashCode,用于JPA识别主键唯一性 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DeliveryId that = (DeliveryId) o; return deliveryId == that.deliveryId && invoiceInvoiceId == that.invoiceInvoiceId; } @Override public int hashCode() { return Objects.hash(deliveryId, invoiceInvoiceId); } // getter和setter方法 public int getDeliveryId() { return deliveryId; } public void setDeliveryId(int deliveryId) { this.deliveryId = deliveryId; } public int getInvoiceInvoiceId() { return invoiceInvoiceId; } public void setInvoiceInvoiceId(int invoiceInvoiceId) { this.invoiceInvoiceId = invoiceInvoiceId; } }
第二步:修改Delivery实体类
用@EmbeddedId引用上面的复合主键类,然后通过@MapsId关联Invoice实体,指定对应的主键字段:
import jakarta.persistence.*; @Entity(name = "delivery") public class Delivery { @EmbeddedId private DeliveryId id; @OneToOne @MapsId("invoiceInvoiceId") // 指定复合主键中的invoiceInvoiceId字段,关联到Invoice的主键 @JoinColumn(name = "invoice_invoiceId", unique = true) private Invoice invoice; // 无参构造函数 public Delivery() {} // 带参数的构造函数 public Delivery(DeliveryId id, Invoice invoice) { this.id = id; this.invoice = invoice; } // getter和setter方法 public DeliveryId getId() { return id; } public void setId(DeliveryId id) { this.id = id; } public Invoice getInvoice() { return invoice; } public void setInvoice(Invoice invoice) { this.invoice = invoice; } }
第三步:修改Invoice实体类
Invoice的主键是自己的invoiceId,之前错误地把Delivery作为主键,现在修正为独立主键,同时配置@OneToOne的反向关联:
import jakarta.persistence.*; @Entity(name = "invoice") public class Invoice { @Id @GeneratedValue(strategy = GenerationType.AUTO) // 可根据业务需求调整主键生成策略 private int invoiceId; @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "invoice") private Delivery delivery; // 无参构造函数 public Invoice() {} // getter和setter方法 public int getInvoiceId() { return invoiceId; } public void setInvoiceId(int invoiceId) { this.invoiceId = invoiceId; } public Delivery getDelivery() { return delivery; } public void setDelivery(Delivery delivery) { this.delivery = delivery; } }
为什么之前的代码会报错?
- 重复的@Id注解:你在Delivery类里给
deliveryId和invoice都加了@Id,这会让Hibernate无法正确识别复合主键的结构,导致初始化SessionFactory时出现空指针异常。 - Invoice主键配置错误:Invoice的主键应该是自己的
invoiceId,而不是关联的Delivery实体,这会破坏实体映射的逻辑。
这样配置后,Hibernate就能正确识别Delivery表的复合主键,同时维护好Invoice和Delivery之间的一对一关联关系啦~
内容的提问来源于stack exchange,提问作者sajithneyo
相关产品推荐
相关产品推荐

