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

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; }
}

为什么之前的代码会报错?

  1. 重复的@Id注解:你在Delivery类里给deliveryId和invoice都加了@Id,这会让Hibernate无法正确识别复合主键的结构,导致初始化SessionFactory时出现空指针异常。
  2. Invoice主键配置错误:Invoice的主键应该是自己的invoiceId,而不是关联的Delivery实体,这会破坏实体映射的逻辑。

这样配置后,Hibernate就能正确识别Delivery表的复合主键,同时维护好Invoice和Delivery之间的一对一关联关系啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:54:43