Spring JPA/Hibernate:非主键列多态关联映射及MappingException报错解决
先还原下你的代码和遇到的异常情况:
你的实体类B的映射代码如下:
class B { @Any(metaColumn = @Column(name = "ITEM_TYPE")) @AnyMetaDef(idType = "long", metaType = "string", metaValues = { @MetaValue(targetEntity = A.class, value = "A") }) @Cascade( { org.hibernate.annotations.CascadeType.ALL}) @JoinColumn(name = "ITEM_ID") private A a; // ... 其他代码 }
抛出的异常信息:
Caused by: org.hibernate.MappingException: Foreign key (FKi1uuph2wrvxtx66s7n7i1s09a:B [item_type,item_id]) must have same number of columns as the referenced primary key (A [id])
问题根源分析
你这里误用了@Any注解的适用场景。@Any是Hibernate专门用来处理多态关联的,比如你的ITEM_TYPE可能有多个值(比如'A'、'C'、'D'),分别对应不同的实体类。它会自动把metaColumn(也就是ITEM_TYPE)和idColumn(ITEM_ID)组合成复合外键,去关联目标实体的主键。但你的实体A的主键只有id这一列,复合外键(两列)和单主键列不匹配,这就是报错的核心原因。
针对性解决方案
根据你的需求——固定关联ITEM_TYPE='A'的A实体,其实完全不需要用@Any,用@ManyToOne配合@Where注解就能完美解决:
class B { // 关联A实体,通过ITEM_ID匹配A.id @ManyToOne @Cascade(org.hibernate.annotations.CascadeType.ALL) @JoinColumn(name = "ITEM_ID") // 限制只关联ITEM_TYPE为'A'的记录 @Where(clause = "ITEM_TYPE = 'A'") private A a; // 别忘了映射ITEM_TYPE列本身 @Column(name = "ITEM_TYPE") private String itemType; // ... 其他代码 }
这样既满足了B.item_id=A.id的关联条件,又通过@Where注解过滤了ITEM_TYPE='A'的记录,同时避免了@Any带来的复合外键不匹配问题。
如果未来你需要扩展多态关联(比如ITEM_TYPE新增其他值对应不同实体),那再考虑用@Any,但那时要确保每个目标实体的主键都和idType匹配,并且理解@Any会生成复合外键的特性。
内容的提问来源于stack exchange,提问作者Rajneesh Prakash

