使用FetchType.LAZY的JPA实体保存时报IllegalStateException如何解决
错误原因
你触发该错误的核心原因是不符合JPA @IdClass 复合主键的规范要求:
- 当实体类中用
@Id标注的是@ManyToOne关联字段时,对应的@IdClass主键类中,同名字段的类型不能是关联实体本身,必须是关联实体的主键字段类型。 - 你本地Lock、Key实体的主键类型应为UUID,JPA处理复合主键时会直接读取关联字段的主键值(UUID类型),但你现有
LockKeyId中声明的lock、key字段是实体类型,框架找不到UUID转实体的转换策略,因此抛出类型转换异常。
另外你现有LockKeyId只实现了equals方法,缺少hashCode方法,也不符合JPA主键类必须同时实现两个方法的要求,会引发后续主键比对异常。
修复步骤
1. 调整LockKeyId主键类定义
将主键类中的字段类型替换为关联实体的主键类型,同时补全hashCode方法,示例如下(如果你的Lock/Key主键不是UUID,替换为对应类型即可):
open class LockKeyId: Serializable { // 替换为Lock实体的主键类型,这里以UUID为例 lateinit var lock: UUID // 替换为Key实体的主键类型,这里以UUID为例 lateinit var key: UUID override fun equals(other: Any?): Boolean { if (other == null) return false return (other is LockKeyId) && other.lock == this.lock && other.key == this.key } override fun hashCode(): Int { var result = lock.hashCode() result = 31 * result + key.hashCode() return result } }
2. 检查关联实体的状态
你给LockKey赋值的lock、key必须是JPA上下文的托管态实体:要么是从数据库查询返回的实体,要么是已经调用过save方法持久化的实体,不能是手动new出来的未设置主键的游离对象。
调整完成后重新执行原有代码即可正常保存LockKey实例。
内容的提问来源于stack exchange,提问作者mengmeng
相关产品推荐
相关产品推荐

