也许我只是给你一小段代码而过度简化了这一点(如果是这样的话,我会发布更多的代码)但我认为,最初,越少越好:
我有一个Asset类型的实体,它有一个类型为Location的字段,它也是一个实体。当我设置资产的位置时,我还必须设置其子项的位置。
Location location = asset.getLocation();
em.merge(location);
em.flush();
childAsset.setLocation(asset.getLocation());
em.flush();
当我运行flush()时,我得到以下异常:
内部异常:java.sql.SQLIntegrityConstraintViolationException:ORA-00001:违反了唯一约束(SWRADMIN.LOCATION_PK)
我的问题是......为什么这个Location对象甚至试图被持久化?我正在做的就是在实体中设置一个变量。
之前一切正常,但我们只是转而使用Eclipselink和Java EE 6,这个问题就出现了。
解决方案?:我使用了从下面“分离”的想法并进行了以下更改:
Location location = asset.getLocation();
em.detach(childAsset);
childAsset.setLocation(asset.getLocation());
em.merge();
em.flush();
它有效!我很困惑为什么,但是......你会认为自动同步会做同样的事情。
答案 0 :(得分:2)
如果对象处于托管状态,则实体管理器将通过隐式地(可能在事务结束时)持久保存对象或在调用em.flush()
方法时显式地将其与底层数据库同步。
您可以使用em.detach(entity)
分离单个实体,或em.clear()
分离所有实体。然后,对实体/实体所做的更改将不会反映在数据库中。
为了更好地处理这个问题,您可以使用BMT(Bean管理事务),您必须手动处理实体持久性,事务处理。
编辑:
Location location = asset.getLocation();
childAsset.setLocation(location);
em.merge(childAsset);
em.flush();
答案 1 :(得分:0)
那么,该位置是现有位置还是新对象?
它是如何读取的,是从另一个事务或实体管理器读取还是以某种方式分离?如果是这样,那么你需要重新阅读(找到)或合并它。
如果它是新的并且与托管对象相关,则是,flush必须写入它。
答案 2 :(得分:0)
从代码中看起来您正在使用非托管版本的位置并将其与ChildAsset相关联。如果您的childAsset-> Location关系被标记为cascade persist,那么将在flush或commit上的Location上调用spec要求perist。由于Location不是托管对象,因此在持久化时需要例外。
管理位置时(例如,当您在ChildAsset上调用merge时,或者如果您使用了从位置返回的位置的托管实例) em.merge(位置);调用),对ChildAsset的持续操作 - >位置是无操作。
不要将非托管实体与标记为级联持久的关系相关联。