JPA实体@OneToOne复合主键配置求助(IdClass方式)
JPA实体配置问题解答
问题1:Inbox的PK类应使用String类型,而非实体类型
JPA的@IdClass要求主键类的属性必须与实体中所有@Id注解属性的主键类型匹配,且属性名需与实体中的关联属性名保持一致。
在你的Inbox实体中,@Id标记的是Company和Document类型的关联属性,但这两个实体的主键都是String类型。因此PK类需要定义对应类型的属性,而非实体本身:
public class PK implements Serializable { // 属性名要和Inbox中的@Id关联属性名一致 private String company; private String document; // 必须实现equals和hashCode方法,以及无参构造器 public PK() {} public PK(String company, String document) { this.company = company; this.document = document; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PK pk = (PK) o; return Objects.equals(company, pk.company) && Objects.equals(document, pk.document); } @Override public int hashCode() { return Objects.hash(company, document); } }
核心问题:Invoice实体的IdClass配置
要实现Invoice以(company_id, document_id)作为主键并关联Inbox,需遵循以下规则:
Invoice的@IdClass主键类需包含与Inbox主键对应的两个String类型属性,属性名要和Invoice中定义的主键属性名一致。Invoice与Inbox的@OneToOne关联需通过两个@JoinColumn绑定到Inbox的主键列,同时这两个列也是Invoice的主键列。- 使用
@MapsId将关联的Inbox主键映射到Invoice的主键属性。
完整Invoice实体代码
@Entity @IdClass(Invoice.PK.class) public class Invoice implements Serializable { // 定义两个主键属性,对应company_id和document_id @Id private String companyId; @Id private String documentId; // 关联Inbox实体,通过@JoinColumn绑定到Inbox的主键列 @OneToOne(fetch = FetchType.LAZY) @MapsId // 将Inbox的主键映射到当前实体的主键属性 @JoinColumns({ @JoinColumn(name = "company_id", referencedColumnName = "company"), @JoinColumn(name = "document_id", referencedColumnName = "document") }) private Inbox inbox; // 主键类:属性名需与Invoice中的@Id属性名完全一致 public static class PK implements Serializable { private String companyId; private String documentId; public PK() {} public PK(String companyId, String documentId) { this.companyId = companyId; this.documentId = documentId; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PK pk = (PK) o; return Objects.equals(companyId, pk.companyId) && Objects.equals(documentId, pk.documentId); } @Override public int hashCode() { return Objects.hash(companyId, documentId); } } // getter/setter省略 }
关键说明
@MapsId的作用是将关联实体Inbox的主键值自动同步到Invoice的主键属性中,无需手动设置companyId和documentId。@JoinColumns中的referencedColumnName要对应Inbox表中存储Company和Document主键的列名(默认JPA会生成company_id和document_id,如果你的表列名不同需调整)。- 主键类
PK必须实现Serializable,且拥有无参构造器、正确的equals和hashCode方法,这是JPA的强制要求。
同时需要调整Inbox中的Invoice关联,将mappedBy改为inbox(因为Invoice中关联属性的名字是inbox):
@OneToOne(fetch = FetchType.LAZY, mappedBy = "inbox") private Invoice invoice;
内容的提问来源于stack exchange,提问作者SteveGot
相关产品推荐
相关产品推荐

