2010-03-11 9 views
40

मुझे एक डीएओ मिला है जिसे मैं जेपीए का उपयोग करके अपने डोमेन ऑब्जेक्ट्स को लोड और सहेजता था। अंत में लेनदेन सामान काम करने में कामयाब रहा, अब मुझे एक और मुद्दा मिला है।जेपीए सोचता है कि मैं एक अलग ऑब्जेक्ट को हटा रहा हूं

मेरे परीक्षण मामले में, मैं किसी दिए गए आईडी के साथ एक डोमेन ऑब्जेक्ट लोड करने के लिए अपने डीएओ को कॉल करता हूं, जांचता हूं कि यह लोड हो गया है और फिर उसी ऑब्जेक्ट को कॉल करने के लिए उसी डीएओ को कॉल करें जिसे मैंने अभी लोड किया था।

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) 

अब यह देखते हुए कि मैं एक ही डीएओ उदाहरण का उपयोग कर रहा है, और मैं नहीं बदल दिया है EntityManagers (जब तक वसंत तो दे मुझे पता है बिना करता है), यह कैसे हो सकता है: जब मैं कि मैं निम्नलिखित मिलता है एक अलग वस्तु?

मेरे डीएओ कोड इस तरह दिखता है:

परीक्षण का मामला कोड की तरह दिखता है:

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); 

किसी को भी मुझे बता सकते हैं मैं गलत यहाँ क्या कर रहा हूँ?

उत्तर

66

मुझे लगता है कि आप तो अपने find और delete संचालन एक सौदे के बाहर अपने कोड द्वारा चलाए जा रहे एक अलग हठ संदर्भ में पाए जाते हैं और find वास्तव में एक अलग उदाहरण देता है (ताकि जेपीए सही है और आप को हटाने के लिए एक अलग हैं वस्तु)।

लेनदेन के अंदर अपना ढूंढ/हटाएं अनुक्रम लपेटें।

अद्यतन: अध्याय 7.3.1. Transaction Persistence Context का एक अंश नीचे:

आप एक सक्रिय लेन-देन के बाहर एक सौदे हठ संदर्भ मॉडल के साथ एक EntityManager उपयोग करते हैं, प्रत्येक विधि मंगलाचरण एक नया हठ संदर्भ बनाता है, प्रदर्शन विधि कार्रवाई, और दृढ़ता संदर्भ समाप्त होता है। उदाहरण के लिए, लेनदेन के बाहर EntityManager.find विधि का उपयोग करने पर विचार करें। EntityManager अस्थायी दृढ़ता संदर्भ बनाएगा, खोज ऑपरेशन निष्पादित करेगा, दृढ़ता संदर्भ समाप्त करेगा, और अलग-अलग परिणाम ऑब्जेक्ट को आपके पास वापस कर देगा। एक ही आईडी के साथ एक दूसरी कॉल एक दूसरी अलग वस्तु वापस कर देगा।

+7

वास्तव में मेरे लिए जवाबी सहज लगता है कि: तो entityManager.remove() चेक जारी करता है, तो इकाई से जुड़ा हुआ है, अगर enitityManger.merge(entity) का उपयोग कर इसे संलग्न नहीं है और फिर उस पर entityManager.remove जारी इस प्रकार से पहले। क्या मुझे वास्तव में एक ऐसे ऑपरेशन को लपेटने की ज़रूरत है जो लेनदेन में डेटाबेस (खोज()) को प्रभावित न करे, बस मैं इसे हटा सकता हूं (या सहेज सकता हूं या अपडेट कर सकता हूं)? – Steve

+0

काउंटर-अंतर्ज्ञानी हालांकि यह हो सकता है, यह काम करता है। ऐसा लगता है कि मुझे अपने डीएओ डिजाइन को पूरी तरह से पुनर्विचार करने की आवश्यकता है। यह * हर * ऑपरेशन की तरह लगता है जो अंततः एक इकाई को संशोधित करेगा, पहले एक खोज करना होगा (उसी लेनदेन के तहत जिसका उपयोग इकाई को लिखने के लिए किया जाएगा)। – Steve

+0

@Steve आप इसे सहज समझ सकते हैं लेकिन इस तरह चीजें काम करती हैं। यदि आप किसी लेन-देन के बाहर 'ढूंढ' का उपयोग करते हैं, तो आपको एक अलग इकाई मिल जाएगी। –

14

पास्कल थिवेंट की पोस्ट में +1 और केवल एक फॉलोअप।

@Transactional 
    public void remove(long purchaseId){ 
     Purchase attached = jpaTemplate.find(Purchase.class,purchaseId); 
     jpaTemplate.remove(attached); 
    } 
32
public void remove(Object obj){ 
    em.remove(em.merge(obj)); 
} 

ऊपर कोड द्वारा zawhtut

+1

जेनेरिक हटाने के लिए बहुत अच्छा समाधान है, क्योंकि आपको कुंजी को जानने की आवश्यकता नहीं है। –

+0

आपने मुझे बचाया :) – vinod

6

प्रस्तावित के समान है em.getReference() बजाय em.find() का उपयोग करके उदाहरण प्राप्त करें।

उदाहरण के लिए, कोशिश:

em.remove(em.getReference(INTFC.class, id)); 
+0

तो क्या यह डेटाबेस से पूछताछ से बचता है? – Pawan

3

यहाँ मैं क्या प्रयोग किया जाता है (पिछले उत्तरों के आधार)

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(); 
} 
0

लेन-देन एसिड गुण सुनिश्चित करता है लेकिन नहीं इकाई संलग्न या अलग है या नहीं। यदि आप एक ही लेनदेन में entityManager.find और 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); 
    } 
संबंधित मुद्दे

 संबंधित मुद्दे