JPA复合主键层级映射问题:配置Answers实体启动报错
问题原因与解决建议
问题根源
你的Question实体使用复合主键(id + cate_id),而JPA关联实体时,必须用关联目标的完整主键来建立外键关系。你当前的Answer实体仅通过question_id关联Question,缺少了Question主键的另一部分cate_id,导致Hibernate无法找到完整的关联匹配字段,从而抛出Unable to find column reference in the @MapsId mapping: cate_id错误。
另外从数据库设计角度看,原answers表仅存储question_id不严谨——不同分类下存在相同的question_id(比如C1和C2下都有Q1),仅靠question_id无法唯一定位一个Question记录,必须同时存储对应的cate_id。
解决方案
下面提供两种可行的映射方案:
方案一:扩展AnswerId并配置多字段关联
- 修改
AnswerId嵌入类,添加cate_id对应的字段:
@Embeddable public class AnswerId implements Serializable { @Column(name = "id") private Long id; @Column(name = "question_id") private Long questionId; @Column(name = "cate_id") private Long categoryId; // 实现构造方法、hashCode()、equals()方法 }
- 调整
Answer实体的关联配置,通过@JoinColumns指定完整的外键匹配:
@Entity @Table(name = "answers") public class Answer { @EmbeddedId private AnswerId id; @ManyToOne @MapsId({"questionId", "categoryId"}) // 映射Question复合主键的两个字段 @JoinColumns({ @JoinColumn(name = "question_id", referencedColumnName = "id"), @JoinColumn(name = "cate_id", referencedColumnName = "cate_id") }) private Question question; // 其他字段与方法 }
方案二:在AnswerId中直接嵌入QuestionId(更符合JPA规范)
这种方式直接复用Question的复合主键定义,逻辑更清晰:
- 修改
AnswerId嵌入类,嵌入QuestionId:
@Embeddable public class AnswerId implements Serializable { @Column(name = "id") private Long id; @Embedded private QuestionId questionId; // 实现构造方法、hashCode()、equals()方法 }
- 调整
Answer实体的关联配置:
@Entity @Table(name = "answers") public class Answer { @EmbeddedId private AnswerId id; @ManyToOne @MapsId("questionId") // 映射到AnswerId中的questionId字段 @JoinColumns({ @JoinColumn(name = "question_id", referencedColumnName = "id"), @JoinColumn(name = "cate_id", referencedColumnName = "cate_id") }) private Question question; // 其他字段与方法 }
注意事项
如果使用H2内存库并开启spring.jpa.hibernate.ddl-auto=create,Hibernate会自动为answers表添加cate_id字段;如果是现有数据库,需要手动给answers表添加cate_id字段,否则会出现表结构不匹配的问题。
内容的提问来源于stack exchange,提问作者Witek
相关产品推荐
相关产品推荐

