Hibernate单向一对一映射报错:IdentifierGenerationException空ID生成
问题根源
PersonStatusEntity的@Id同时配置了@GeneratedValue和@MapsId,两者冲突:@MapsId指定ID来源于关联的Person实体,但@GeneratedValue又试图让数据库自增生成ID,导致Hibernate无法确定ID生成逻辑,最终抛出空ID异常。- 单向一对一关系的维护方配置错误:未明确指定关系由
PersonStatus侧维护,导致Hibernate无法将Person的ID传递给PersonStatus。
正确配置代码
PersonEntity.kt
@Entity(name = "Person") class PersonEntity( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, val name: String, @OneToOne( mappedBy = "person", // 指定关系由PersonStatus的person字段维护 cascade = [CascadeType.ALL], fetch = FetchType.LAZY, optional = false, orphanRemoval = true ) var personStatus: PersonStatusEntity )
PersonStatusEntity.kt
@Entity(name = "PersonStatus") class PersonStatusEntity( @Id var id: Long? = null, // 移除@GeneratedValue,ID由关联的Person提供 @OneToOne(fetch = FetchType.LAZY) @MapsId // 将当前实体的id与关联Person的id绑定 var person: PersonEntity, // 改为非空,匹配Person中optional=false的约束 @Enumerated(EnumType.STRING) val status: Status )
正确保存方式
保存时必须先建立Person与PersonStatus的关联,再持久化Person(级联操作会自动保存PersonStatus):
val personStatus = PersonStatusEntity(status = Status.ACTIVE, person = null) val person = PersonEntity(name = "测试用户", personStatus = personStatus) personStatus.person = person // 建立关联,确保PersonStatus能获取到Person的ID entityManager.persist(person)
表结构说明
如果要完全遵循Hibernate推荐的高效方案,person_status表不需要单独的person_id字段,直接用主键id作为外键关联person表的id即可,减少冗余字段提升性能。如果坚持保留person_id字段,@MapsId并不适用,此时应移除@MapsId,在PersonStatus的person字段上添加@JoinColumn(name = "person_id"),同时恢复PersonStatus的@Id上的@GeneratedValue配置。
内容的提问来源于stack exchange,提问作者Kartik
相关产品推荐
相关产品推荐

