У меня есть DAO, который я использовал для загрузки и сохранения объектов домена с помощью JPA. Наконец-то мне удалось заставить работать транзакцию, теперь у меня другая проблема.JPA думает, что я удаляю отдельный объект
В моем тестовом примере я вызываю свой DAO для загрузки объекта домена с заданным идентификатором, проверьте, чтобы он был загружен, а затем вызвал тот же 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 (если весна не делает это, не давая мне знать), как это может быть отдельный объект?
Мой DAO код выглядит следующим образом: Код случай
Тест выглядит следующим образом:
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()) в транзакции, чтобы я мог удалить (или сохранить или обновить) ее? – Steve
Контринтуитивный, хотя может быть, он действительно работает. Это, по-видимому, означает, что мне нужно полностью переосмыслить мой дизайн DAO. Это звучит как * каждая * операция, которая в конечном итоге изменит Entity, придется сначала выполнить поиск (под той же транзакцией, которая будет использоваться для записи Entity). – Steve
@Steve Вы можете обнаружить, что это противоречит интуитивному, но это то, как все работает. Если вы используете 'find' вне транзакции, вы получите отдельный объект. –