Hibernate如何映射关联另一复合主键的复合主键实体
Hibernate 复合主键关联复合主键的正确映射方案
报错的核心原因是Role实体使用包含siteId、id两个字段的复合主键CommonId,因此关联Role时需要两个列才能定位唯一实例,而原有映射只提供了role_id一个列,导致Hibernate校验不通过。
修改方案
1. 无需调整的代码
UserSiteRoleId嵌入式主键定义完全符合表结构,可以保留原有逻辑:
@Embeddable public class UserSiteRoleId implements Serializable { @Type(type = "pg-id-uuid") @Column(columnDefinition = "uuid", updatable = false) private UUID userId; @Type(type = "pg-id-uuid") @Column(name = "site_id", columnDefinition = "uuid", updatable = false) private UUID siteId; @Type(type = "pg-id-uuid") @Column(name = "role_id", columnDefinition = "uuid", updatable = false) private UUID roleId; }
2. 调整UserSiteRole实体的Role关联逻辑
核心修改点是用@JoinColumns指定双外键映射,复用已有的site_id字段避免重复映射:
@Entity @Table(name = "user_site_roles", schema = "core") @Data @TypeDefs({ @TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class) }) public class UserSiteRole extends AuditCreated implements Serializable { @EmbeddedId private UserSiteRoleId userSiteRoleId; @ManyToOne @MapsId("userId") @JoinColumn(name = "user_id", columnDefinition = "uuid", nullable = false) @OnDelete(action = OnDeleteAction.CASCADE) private User user; @ManyToOne @MapsId("siteId") @JoinColumn(name = "site_id", columnDefinition = "uuid", nullable = false) @OnDelete(action = OnDeleteAction.CASCADE) private Site site; // 仅修改Role关联部分即可 @ManyToOne @MapsId("roleId") @JoinColumns(value = { @JoinColumn(name = "site_id", referencedColumnName = "site_id", insertable = false, updatable = false), @JoinColumn(name = "role_id", referencedColumnName = "id", nullable = false) }) @OnDelete(action = OnDeleteAction.CASCADE) private Role role; }
关键说明
- 用
@JoinColumns指定两个外键列,完全匹配外键约束user_site_roles_role_id_fkey的定义,对应roles表的复合主键 site_id列已经被Site关联的@MapsId("siteId")映射,因此设置insertable = false, updatable = false避免重复映射冲突- 持久化
UserSiteRole实例时,只需正常赋值site、user、role属性,Hibernate会自动填充UserSiteRoleId的三个主键字段,无需手动设置 - 你提供的
user_site_roles建表脚本中,user_id外键定义末尾缺少逗号,执行前需要补充修正,避免建表失败
内容的提问来源于stack exchange,提问作者arkhadi
相关产品推荐
相关产品推荐

