如何使用非主键复合键关联JPA实体?
可以使用非主键复合键关联实体,但你的映射配置存在问题
问题原因分析
抛出的异常org.hibernate.AnnotationException: referencedColumnNames(domain_object_id, tenant_id) of ProductEntity.kind referencing KindEntity not mapped to a single property,核心原因是:
你在ProductEntity的@JoinColumns中指定的关联列,在KindEntity里是封装在TenantEntityDomainObjectTuple这个嵌入式对象中的,Hibernate无法直接识别分散在嵌入式对象中的多个字段作为关联目标;另外你的实体映射还存在数据库列名不匹配的问题(实体中写的wine_kind对应数据库表的kind列)。
解决方案
方案1:暴露目标实体的单独属性
在KindEntity中直接映射domain_object_id和tenant_id字段,让Hibernate能明确识别关联的目标属性:
@Entity @Table(name = "kind", uniqueConstraints = @UniqueConstraint(columnNames = {"tenant_id", "domain_object_id"})) public class KindEntity { @Id @GeneratedValue private long id; // 新增单独字段映射,与嵌入式对象共享数据库列 @Column(name = "domain_object_id", nullable = false) private String domainObjectId; @Column(name = "tenant_id", nullable = false) private String tenantId; @NaturalId @Embedded @AttributeOverrides({ @AttributeOverride(name = "domain_object_id", column = @Column(name = "domain_object_id", insertable = false, updatable = false)), @AttributeOverride(name = "tenant_id", column = @Column(name = "tenant_id", insertable = false, updatable = false)) }) private TenantEntityDomainObjectTuple domainObjectTuple; @Column(name = "display_name", nullable = false) private String displayName; // Getters & Setters }
然后修正ProductEntity中的关联配置(修正列名错误+指向单独属性):
@Entity @Table(name = "product") public class ProductEntity { // ... 其他属性保持不变 @ManyToOne @JoinColumns(value = { @JoinColumn(name = "kind", referencedColumnName = "domainObjectId", insertable = false, updatable = false), @JoinColumn(name = "tenant_id", referencedColumnName = "tenantId", insertable = false, updatable = false) }, foreignKey = @ForeignKey(name = "product_kind_tenant_id_fkey")) private KindEntity kind; }
方案2:关联嵌入式对象的属性路径(Hibernate 5.2+支持)
如果不想新增单独字段,可以直接通过嵌入式对象的属性路径关联,referencedColumnName使用嵌入式属性名.属性的格式:
@Entity @Table(name = "product") public class ProductEntity { // ... 其他属性保持不变 @ManyToOne @JoinColumns(value = { @JoinColumn(name = "kind", referencedColumnName = "domainObjectTuple.domainObjectId", insertable = false, updatable = false), @JoinColumn(name = "tenant_id", referencedColumnName = "domainObjectTuple.tenantId", insertable = false, updatable = false) }, foreignKey = @ForeignKey(name = "product_kind_tenant_id_fkey")) private KindEntity kind; }
关键注意点
- 确保关联的目标列(
kind表的tenant_id和domain_object_id)有唯一约束,这是Hibernate允许非主键关联的前提,你的数据库已经配置了unique (tenant_id, domain_object_id),实体中也可以通过@UniqueConstraint同步配置。 - 严格保持实体映射的列名与数据库表列名一致,避免拼写错误。
内容的提问来源于stack exchange,提问作者domids
相关产品推荐
相关产品推荐

