JPA1.x升级至2.x时不级联保存AddressType的持久化报错解决方案咨询
JPA 2.x迁移关联未托管对象报错解决方案
报错根本原因
该报错是JPA 2.x相比JPA 1.x增强了持久化对象图状态校验导致的:当你执行flush/持久化Addresses实例时,关联的addressType字段对应的对象处于未托管/游离状态,且未配置级联持久化策略,JPA无法处理该未托管关联,因此抛出异常。
你之前配置cascade = CascadeType.PERSIST虽然解决了报错,但如果addressType是临时对象时会自动级联插入,不符合你不需要级联保存AddressType的需求,可以选择以下更适配的解决方案:
可选解决方案
方案1:保存前获取托管状态的AddressType(最常用,推荐)
不要直接将游离态/手动new的AddressType对象赋值给关联字段,先通过持久化上下文API获取托管态的实例再赋值,不需要修改任何注解配置,也不会触发额外的AddressType保存操作:
// 假设你已经拿到要关联的addressTypeId AddressType managedAddressType = entityManager.getReference(AddressType.class, addressTypeId); // 也可以用find方法查询全量对象:entityManager.find(AddressType.class, addressTypeId); addresses.setAddressType(managedAddressType); // 再执行Addresses的持久化操作 entityManager.persist(addresses);
方案2:手动将游离的AddressType转为托管状态
如果你持有的addressType是已经脱离当前持久上下文的游离对象(比如之前其他查询返回的实例),可以先调用merge方法获取托管实例再赋值,只要addressType在数据库已存在,该操作不会触发额外的插入或更新:
AddressType managedAddressType = entityManager.merge(unmanagedAddressType); addresses.setAddressType(managedAddressType); entityManager.persist(addresses);
方案3:跨上下文场景开启跨上下文引用许可
如果你的addressType实例属于另一个持久化上下文,可以直接调用StoreContext.setAllowReferenceToSiblingContext(true)开启跨上下文引用许可,不需要修改关联注解,也不会触发级联保存。
注:不推荐使用全局开启cascade-persist的方案,会导致所有关联默认开启级联持久化,容易出现误插入数据的问题。
内容的提问来源于stack exchange,提问作者SumiSujith
相关产品推荐
相关产品推荐

