2009-07-13 10 views
8

को संरक्षित करने वाली इकाई के प्रकार को बदलना मैं दृढ़ता परत के रूप में हाइबरनेट का उपयोग कर रहा हूं। एक ही टेबल में रहने वाली 2 इकाइयां हैं जो एकल टेबल विरासत रणनीति के साथ एक सुपरक्लास को विस्तारित करती हैं।अपनी आईडी

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
public abstract class A { 
    @Id 
    @GeneratedValue 
    protected Long id; 

    // some common fields for B and C 
} 


@Entity 
public class B extends A { 
    // B-specific fields 
} 

@Entity 
public class C extends A { 
    // C-specific fields 
} 

मेरे पास आईडी = 4 के साथ बी का एक उदाहरण है। मैं इस उदाहरण के प्रकार को अपने आईडी (4) को संरक्षित करने के लिए कैसे बदलूं?

B b = em.find(B.class, 4L); 
C c = convertToC(b); 
c.setId(b.getId()); 
em.remove(b); 
em.persist(c); 

कोड ऊपर

org.hibernate.PersistentObjectException: detached entity passed to persist: C 

के साथ विफल हो यह बिल्कुल संभव है?

+0

यह कैसे विफल हो जाता है? – skaffman

+0

मैंने प्रश्न – artemb

+0

पर अपवाद जोड़ा है बस एक झटका, लेकिन क्या आपने लगातार() के बजाय विलय() को कॉल करने का प्रयास किया है? – skaffman

उत्तर

11

हाइबरनेट दृढ़ता को यथासंभव पारदर्शी बनाने की कोशिश करता है - जिसका अर्थ है कि यह सामान्य जावा ऑब्जेक्ट्स के समान सिद्धांतों का पालन करने का प्रयास करता है।अब, जावा में अपने प्रश्न को फिर से भरना, आपको मिल जाएगा:

मैं बी वर्ग के उदाहरण को (असंगत) सी कक्षा के उदाहरण में कैसे परिवर्तित कर सकता हूं?

और आप इसका उत्तर जानते हैं - आप नहीं कर सकते। आप नया सी के उदाहरण बना सकते हैं और आवश्यक विशेषताओं की प्रतिलिपि बना सकते हैं, लेकिन बी हमेशा बी हो, कभी सी नहीं। इस प्रकार आपके मूल प्रश्न का उत्तर यह है - यह जेपीए या हाइबरनेट एपीआई के माध्यम से नहीं किया जा सकता है।

हालाँकि, सादा जावा, हाइबरनेट के साथ :-) InheritanceType.SINGLE_TABLE धोखा कर सकते हैं @DiscriminatorColumn का उपयोग करने और आदेश सी आप अपने मूल्य जो कुछ भी से जो कुछ भी सी चाल के लिए निर्दिष्ट में बी के लिए निर्दिष्ट है अद्यतन करने की आवश्यकता में बी कन्वर्ट करने के लिए में मैप किया गया है के विपरीत है - आप इसे हाइबरनेट एपीआई का उपयोग करके नहीं कर सकते हैं; आपको सादे एसक्यूएल के माध्यम से इसे करने की ज़रूरत है। हालांकि, आप इस अद्यतन कथन को एसक्यूएल क्वेरी नाम के रूप में मैप कर सकते हैं और हाइबरनेट सुविधाओं का उपयोग करके इसे निष्पादित कर सकते हैं।

एल्गोरिथ्म, इसलिए, यह है:

  1. बेदखल सत्र से बी अगर यह नहीं है (यह महत्वपूर्ण है)
  2. अपने नामित क्वेरी निष्पादित।
  3. पूर्व बी के आईडी का उपयोग करके अब-सी-अब-ज्ञात-सी लोड करें।
  4. आवश्यकतानुसार अपडेट/सेट विशेषताएँ।
  5. पर्सिस्ट सी
2

इस मामले में, "सी" एक ऐसी वस्तु है जिसे हाइबरनेट सत्र के बारे में कुछ नहीं पता है, लेकिन इसमें एक आईडी है, इसलिए यह मानता है कि ऑब्जेक्ट पहले से ही जारी है। उस संदर्भ में, जारी रखें() को कोई समझ नहीं आता है, और इसलिए यह विफल हो जाता है।

हाइबरनेट सत्र के लिए जावाडोक() (मुझे पता है कि आप हाइबरनेट एपीआई का उपयोग नहीं कर रहे हैं, लेकिन अर्थशास्त्र एक जैसे हैं, और हाइबरनेट डॉक्स बेहतर हैं) कहते हैं, "एक क्षणिक उदाहरण लगातार बनाएं"। यदि आपके ऑब्जेक्ट में पहले से ही एक आईडी है, तो यह क्षणिक नहीं है। इसके बजाए, ऐसा लगता है कि यह एक अलग उदाहरण है (यानी एक उदाहरण जो जारी रहा है, लेकिन वर्तमान सत्र से जुड़ा हुआ नहीं है)।

मेरा सुझाव है कि आप लगातार() के बजाय विलय() का प्रयास करें।

+0

अपवाद के कारण को समझाने के लिए धन्यवाद, मुझे यह याद आएगा। विलय विफल नहीं होता है, लेकिन सेट किया गया है कि अनदेखा, "सी" एक नई आईडी देता है। – artemb

0

आप अपनी खुद की आईडी का उपयोग कर सकते हैं (उत्पन्न नहीं) और निम्न करें:

  1. पुनर्प्राप्त बी
  2. खुला लेन-देन
  3. हटाना बी
  4. लेन-देन के लिए प्रतिबद्ध
  5. एक नई लेन-देन को खोलने
  6. सी बनाएं और इसे जारी रखें
  7. दूसरा ट्रांस बंद करें कार्रवाई

इस तरह आप यह सी

+0

इसे लागू करना काफी कठिन होगा। मेरी सभी संस्थाएं autoincremented आईडी का उपयोग करें। क्या उत्पन्न आईडी के मूल्य को मजबूर करने का कोई तरीका है? – artemb

0

आप तालिका में दो संस्थाओं के बीच भेद कैसे कर पाउंगा के रूप में पुन: डालने से पहले मेज से आईडी साफ हो जाएगा? मुझे लगता है कि कुछ फ़ील्ड मान (या मान) हैं जिन्हें आप बी में सी बनाने के लिए बदल सकते हैं?

आपके पास एक तरीका हो सकता है जहां आप सुपर-क्लास ए लोड करते हैं और विशिष्ट मानों को बदलते हैं और सहेजते हैं। फिर आपके अगले हाइबरनेट सत्र में आपका बी एक सी

+0

हाइबरनेट डेटा लोड करते समय तुरंत किस वर्ग को तत्काल करने की आवश्यकता है यह निर्धारित करने के लिए भेदभावकर्ता कॉलम का उपयोग करता है। कॉलम का मान कक्षा के सरल नाम के बराबर है। क्या आप टेबल डेटा को संशोधित करने के लिए सादे एसक्यूएल का उपयोग करने का सुझाव देते हैं? मुझे आपके सुझाव देने का एक और तरीका नहीं दिखता है। – artemb

0

मुझे लगता है कि आईडी के सेट होने के बाद स्काफमैन ठीक है, यह जारी नहीं रहेगा, और आगे क्योंकि आईडी उत्पन्न होती है, यह अनुक्रम में होने की अपेक्षा करता है आईडी नंबर असाइन करने का शुल्क।

आप शायद आईडी को @GeneratedValue के रूप में नहीं डाल सकते? या एक अलग अनुक्रम मूल्य उत्पन्न करने में विलय से बचने के लिए अलग जनरेटर रणनीति प्रकारों में से एक, लेकिन मुझे संदेह है कि यह समस्याग्रस्त होगा।