JPA认为我正在删除一个分离的对象
我有一个使用JPA加载和保存域对象的DAO。 我终于设法得到交易的东西工作,现在我有另一个问题。
在我的testing案例中,我打电话给我的DAO加载一个给定id的域对象,检查它是否被加载,然后调用相同的DAO删除刚加载的对象。 当我这样做时,我得到以下内容:
java.lang.IllegalArgumentException: Removing a detached instance mil.navy.ndms.conops.common.model.impl.jpa.Group#10 at org.hibernate.ejb.event.EJB3DeleteEventListener.performDetachedEntityDeletionCheck(EJB3DeleteEventListener.java:45) at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:108) at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:74) at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:794) at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:772) at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:253) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37) at java.lang.reflect.Method.invoke(Method.java:600) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:180) at $Proxy27.remove(Unknown Source) at mil.navy.ndms.conops.common.dao.impl.jpa.GroupDao.delete(GroupDao.java:499) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37) at java.lang.reflect.Method.invoke(Method.java:600) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) at $Proxy28.delete(Unknown Source) at mil.navy.ndms.conops.common.dao.impl.jpa.GroupDaoTest.testGroupDaoSave(GroupDaoTest.java:89) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37) at java.lang.reflect.Method.invoke(Method.java:600) at junit.framework.TestCase.runTest(TestCase.java:164) at junit.framework.TestCase.runBare(TestCase.java:130) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:120) at junit.framework.TestSuite.runTest(TestSuite.java:230) at junit.framework.TestSuite.run(TestSuite.java:225) at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
现在考虑到我正在使用相同的DAO实例,而且我还没有更改EntityManagers(除非Spring没有让我知道),那么这怎么可能是一个分离的对象呢?
我的DAO代码如下所示:
public class GenericJPADao<INTFC extends IAddressable, VO extends BaseAddressable> implements IWebDao, IDao<INTFC>, IDaoUtil<INTFC> { private static Logger logger = Logger.getLogger (GenericJPADao.class); protected Class<?> voClass; @PersistenceContext(unitName = "CONOPS_PU") protected EntityManagerFactory emf; @PersistenceContext(unitName = "CONOPS_PU") protected EntityManager em; public GenericJPADao() { super ( ); ParameterizedType genericSuperclass = (ParameterizedType) getClass ( ).getGenericSuperclass ( ); this.voClass = (Class<?>) genericSuperclass.getActualTypeArguments ( )[1]; } ... public void delete (INTFC modelObj, EntityManager em) { em.remove (modelObj); } @SuppressWarnings("unchecked") public INTFC findById (Long id) { return ((INTFC) em.find (voClass, id)); } }
testing用例代码如下所示:
IGroup loadedGroup = dao.findById (group.getId ( )); assertNotNull (loadedGroup); assertEquals (group.getId ( ), loadedGroup.getId ( )); dao.delete (loadedGroup); // - This generates the above exception loadedGroup = dao.findById (group.getId ( )); assertNull(loadedGroup);
有谁能告诉我我在做什么错在这里?
我怀疑你是在一个事务之外运行你的代码,所以你的find
和delete
操作发生在一个单独的持久化上下文中,而find
实际上返回一个分离的实例(所以JPA是正确的,你正在删除一个分离的对象)。
将事务中的查找/删除序列封装起来。
更新:下面7.3.1节的摘录。 事务持久性上下文 :
如果在活动事务之外使用带有事务持久性上下文模型的
EntityManager
,则每个方法调用将创build一个新的持久性上下文,执行方法操作并结束持久性上下文。 例如,考虑在事务外使用EntityManager.find
方法。EntityManager
将创build一个临时持久化上下文,执行查找操作,结束持久化上下文,并将分离的结果对象返回给您。 第二次调用相同的ID将返回第二个分离的对象。
public void remove(Object obj){ em.remove(em.merge(obj)); }
以上代码与zawhtut提出的代码类似
+1帕斯卡Thivent的职位,只是一个后续行动。
@Transactional public void remove(long purchaseId){ Purchase attached = jpaTemplate.find(Purchase.class,purchaseId); jpaTemplate.remove(attached); }
通过使用em.getReference()
而不是em.getReference()
来获取实例。
例如,尝试:
em.remove(em.getReference(INTFC.class, id));
这是我用的(根据以前的答案)
public void deleteTask(int taskId) { Task task = getTask(taskId); //this is a function that returns a task by id if (task == null) { return; } EntityManager em = emf.createEntityManager(); EntityTransaction et = em.getTransaction(); et.begin(); em.remove(em.merge(task)); et.commit(); em.close(); }
事务确保ACID属性,但不确定实体是否连接或分离。 即使您在同一事务中运行了entityManager.find
和entityManager.remove()
,也不能保证该实体将被连接。 所以在发出entityManager.remove()
之前检查实体是否连接,如果没有用enitityManger.merge(entity)
附加它,然后发出entityManager.remove
就可以了,如下:
@Transactional public void delete (long id) { ModelObj modelObj=entityManager.find(ModelObj.class,id); modelObj=entityManager.contains(modelObj)?modelObj:entityManager.merge(modelObj); em.remove (modelObj); }
- 在Python中将XML / HTML实体转换为Unicodestring
- LINQ to Entities不识别方法'Int32 Parse(System.String)'方法,并且此方法不能被转换成存储expression式
- 为什么不使用IoC容器来parsing实体/业务对象的依赖关系?
- types或名称空间名称“对象”不存在于名称空间“System.Data”
- 在HTML中,我可以用&#x2713; 。 有没有相应的X标记?
- 提高entity framework中的批量插入性能
- 如何使用entity framework只更新一个字段?
- 我怎样才能得到在entity framework中插入实体的Id?
- entity framework – 有没有一种方法来自动加载没有包含()的子实体?