Arj*_*jms 33 java hibernate jpa exception
我有一个引用实体Bar的实体Foo:
@Entity
public class Foo {
@OneToOne(cascade = {PERSIST, MERGE, REFRESH}, fetch = EAGER)
public Bar getBar() {
return bar;
}
}
Run Code Online (Sandbox Code Playgroud)
当我坚持使用新的Foo时,它可以获得对新Bar或现有Bar的引用.当它获得一个恰好分离的现有Bar时,我的JPA提供程序(Hibernate)抛出以下异常:
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.example.Bar
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:102)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:636)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:628)
at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:28)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:454)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:645)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:619)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:623)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220)
... 112 more
Run Code Online (Sandbox Code Playgroud)
当我确保管理(附加)Bar的引用或者在关系中省略级联PERSIST时,一切正常.
然而,这两种方案都不是100%令人满意.如果我删除级联持续存在,我显然不能再坚持引用新的Bar了.在持久化之前引用Bar管理需要这样的代码:
if (foo.getBar().getID() != null && !entityManager.contains(foo.getBar())) {
foo.setBar(entityManager.merge(foo.getUBar()));
}
entityManager.persist(foo);
Run Code Online (Sandbox Code Playgroud)
对于一个单独的Bar来说这可能看起来不是什么大问题,但如果我必须考虑所有这些属性,我会最终得到相当糟糕的代码,这似乎首先打败了使用ORM的原因.我也可以再次使用JDBC手动保持我的对象图.
当给定现有Bar引用时,JPA唯一要做的就是获取其ID并将其插入到包含Foo的表的列中.当附加Bar时它会完成此操作,但是当Bar被分离时抛出异常.
我的问题是; 为什么要附加Bar?当Bar实例从分离状态转换为附加状态时,它的ID不会改变,并且该ID似乎是这里唯一需要的东西.
这可能是Hibernate中的一个错误,还是我错过了什么?
axt*_*avt 21
您可以使用merge()
而不是persist()
在这种情况下:
foo = entityManager.merge(foo);
Run Code Online (Sandbox Code Playgroud)
当应用于新实例时,merge()
使其持久化(实际上 - 返回具有相同状态的持久化实例),并在您尝试手动执行时合并级联引用.
如果我理解正确,您只需要Bar
引用以允许new 在持久化时Foo
具有外键值(对现有Bar
).EntityManager
调用了一个JPA方法,getReference()
对于这种情况可能对你有用.该getReference()
方法类似于find()
除了它将不会返回托管实例(of Bar
),除非它恰好已经在持久化上下文中缓存.它将返回一个代理对象,该对象将满足您的外键需求,以便持久保存该Foo
对象.我不确定这是否是您希望的那种解决方案,但请试一试,看看这是否适合您.
我还从您的代码中注意到,您通过注释getter方法(对于Bar
关系)使用"property"样式访问而不是"field"样式访问.有什么理由吗?出于性能原因,建议您注释成员而不是getter.对于JPA提供者而言,它应该更有效地直接访问该字段而不是通过getter和setter.
编辑:
正如其他人所提到的,使用级联merge()将持久保存新实体以及合并已修改的实体并重新附加与MERGE级联选项有关系的分离的entites.使用PERSIST级联选项不会重新附加任何内容或合并任何内容,而是在您想要的行为时使用.
归档时间: |
|
查看次数: |
27972 次 |
最近记录: |