2012-09-11 18 views
7

मेरे पास एक जेपीए प्रोग्राम है जहां EclipseLink Persistence प्रदाता है। जब मैं किसी उपयोगकर्ता इकाई को विलय करता हूं, उसकी आईडी बदलता हूं, और उसी उपयोगकर्ता उदाहरण को फिर से मर्ज करने का प्रयास करता हूं, तो एक त्रुटि फेंक दी जाती है। मैं अपनी समस्या को सबसे सरल तरीके से चित्रित करने के लिए अपने कोड को फिर से लिखता हूं।किसी इकाई को मर्ज करें, उसकी आईडी बदलें, फिर से विलय करें, "डेटाबेस में प्राथमिक कुंजी कॉलम में मैप किया गया है। अपडेट्स की अनुमति नहीं है" त्रुटि

User user = userManager.find(1); 
userManager.merge(user); 
System.out.println("User is managed? "+userManager.contains(user); 
user.setId(2); 
userManager.merge(user); 

उपरोक्त कोड लेनदेन संदर्भ में नहीं है। userManager एक EntessManager इंजेक्शन के साथ एक स्टेटलेस सत्र बीन है। निष्पादित होने पर, कंसोल प्रिंट करता है:

User is managed? false 

Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.1.3.v20110304-r9073): org.eclipse.persistence.exceptions.ValidationException 
Exception Description: The attribute [id] of class [demo.model.User] is mapped to a primary key column in the database. Updates are not allowed. 

अपवाद दूसरे विलय() आमंत्रण पर होता है।

अगर मैं एक नया उपयोगकर्ता बनाने, अपने आईडी सेट करता है और विलय यह, यह काम करता है:

User user = userManager.find(1); 
userManager.merge(user); 
System.out.println("User is managed? "+userManager.contains(user); 
User newUser = new User(); 
newUser.setId(2); 
userManager.merge(newUser); 

तो पहले परिदृश्य और दूसरा एक के बीच अंतर क्या है? जेपीए विनिर्देश के अनुसार, जब तक कि इकाई अलग राज्य में है, विलय सफल होना चाहिए, है ना? (आईडी = 2 के साथ इकाई को मानना)

क्यों EclipseLink प्रदाता को इस तथ्य से परेशान होना प्रतीत होता है कि उपयोगकर्ता इकाई को पहले विलय कर दिया गया है?

अद्यतन: यह ग्रहण लिंक का एक बग प्रतीत होता है। मैं जगह ले ली है EclipseLink से हठ प्रदाता हाइबरनेट करने के लिए:

मैं

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 

बदलने

<provider>org.hibernate.ejb.HibernatePersistence</provider>  

कोई त्रुटि निकाल दिया गया है करने के लिए।

+0

अपने आईडी एक उत्पन्न मूल्य है? – kostja

+0

हां, यह एक उत्पन्न मूल्य –

उत्तर

2

ऐसा लगता है कि यह ग्रहण लिंक का एक बग है। मैं बदल गया है EclipseLink से हठ प्रदाता हाइबरनेट करने के लिए:

से

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 

को

<provider>org.hibernate.ejb.HibernatePersistence</provider> 

कोई त्रुटि फेंक दिया गया है।

एक्लिप्ससेंक का संस्करण 2.3.2 है। (जिसे नवीनतम ग्लासफ़िश एप्लिकेशन सर्वर 3.1.2 के साथ भेज दिया गया है)।

हाइबरनेट का संस्करण अब नवीनतम, 4.1.7 है।

+1

संस्करण 2.6.3 –

3

कारण यह है कि Id डाला/परिभाषित किया जा सकता है - जैसा कि आप अपने दूसरे उदाहरण में करते हैं, लेकिन बदले/अपडेट नहीं होते - जैसे आप अपने पहले उदाहरण में प्रयास करते हैं। जेपीए प्रदाता डेटाबेस में बदलाव को प्रतिबिंबित करने की कोशिश करता है और विफल रहता है।

जेपीए 2 कल्पना §2.4 कहते

आवेदन प्राथमिक कुंजी का मूल्य बदल नहीं होना चाहिए। यदि ऐसा होता है तो व्यवहार अपरिभाषित है।

+0

है लेकिन इकाई पहले ही अलग हो चुकी है। जब आप एक अलग इकाई के आईडी को बदलते हैं, तो परिवर्तन डेटाबेस में दिखाई नहीं देगा। –

+0

@MingtaoSun हाँ, अगर इकाई प्रबंधित नहीं की जाती है, तो त्रुटि 'मर्ज' कॉल पर होनी चाहिए, न कि 'setId' पर। यह कहां होता है? एक अजीब चीज यह है कि ईएम द्वारा लौटाई गई इकाई को प्रबंधित नहीं किया जाता है। ईएम केवल संबंधित प्रेसिजनेंस संदर्भ में निहित वस्तुओं को वापस कर सकता है और इस प्रकार केवल प्रबंधित किए गए हैं। अगर त्रुटि 'setId' पर होती है, तो ईएम पर' डिटेच 'या' स्पष्ट 'को कॉल करके इकाई को स्पष्ट रूप से अलग करने का प्रयास करें। – kostja

+0

त्रुटि आईडी() के बजाय विलय() पर त्रुटि हुई। जेपीए स्पेक के अनुसार, जब इकाई अलग हो जाती है, तो इसे विलय किया जा सकता है()। –

0

इस उत्तर 4 साल देर से लेकिन वैसे भी है के रूप में persistence.xml में <property name="eclipselink.weaving.internal" value="false"/> की कोशिश करो।

आप नियमित अद्यतन को क्रियान्वित करते हुए इसे अपडेट कर सकते एसक्यूएल या JPQL या मानदंड एपीआई का उपयोग कर प्रश्नों। मुझे लगता है कि आखिरी सबसे अच्छा है।

यहां एक कोड उदाहरण है जो चाल कर सकता है। मैंने इसे एक समान स्थिति में आजमाया है और यह एक्लिप्ससेंक के साथ ठीक काम करता है।

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaUpdate<User> cu = cb.createCriteriaUpdate(User.class); 
Root<User> c = cu.from(User.class); 
cu.set(User_.id, newId).where( cb.equal(c.get(User_.id), oldId) ); 
em.createQuery(cu).executeUpdate(); 

के बजाय User_.id आप उदाहरण, एक स्ट्रिंग के रूप में क्षेत्र के नाम पर पारित कर सकते हैं "आईडी"

एक और उदाहरण http://www.thoughts-on-java.org/criteria-updatedelete-easy-way-to/