2009-07-09 18 views
14

में दीप कॉपी मैं जेपीए में एक इकाई की गहरी प्रतिलिपि बनाना चाहता हूं। मुझे यहां एक दिलचस्प चर्चा मिली: http://forums.java.net/jive/thread.jspa?messageID=253092&tstart=0जेपीए

ऐसा लगता है कि प्रस्तावित समाधान सभी @ आईडी को शून्य पर सेट करना था। यहां मेरा मूल कोड है:


//Start a JPA session. 
EntityManager em= emf.createEntityManager(); 
em.getTransaction().begin(); 

//Get the object I want to copy. 
MyClass myObject=em.find(MyClass.class,id); 

//Use reflection to find @Id's and set them to zero for all @OneToMany and @OneToOne relations. 
//TODO: write the ugly recursive code to do this. 

//Hoping this will create a deep copy. 
em.merge(myObject); 

//Close the session. 
em.getTransaction().commit(); 
em.close(); 

क्या यह एक अच्छी रणनीति है? क्या किसी को यह TODO कोड पहले ही लिखा जा सकता है कि वे साझा कर सकते हैं ???

धन्यवाद!

+0

लिंक टूटी हुई है। क्या आप इसे अपडेट कर सकते हैं। – Kayser

+0

क्या आप वाकई एक गहरी प्रतिलिपि बनाना चाहते हैं? इससे पूरे डेटाबेस को डुप्लिकेट किया जा सकता है। मैं प्रतिलिपि को लागू करने के साथ चिपकना चाहूंगा - थकाऊ, लेकिन मुझे सिरदर्द या बदतर बचा सकता है, एक सर्वर उत्पादन में दुर्घटनाग्रस्त हो रहा है। –

उत्तर

2

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

गहरी प्रतियों के लिए उपर्युक्त अन्य सिफारिशें काम नहीं लगतीं। अनुमोदित, समस्या कुंजीपटल और कुर्सी के बीच हो सकती है। लेकिन अब यह काम कर रहा है।

सभी को धन्यवाद!

+4

असल में आपने कहा कि हमें उत्सुकता से पूरे ग्राफ को लोड करने की आवश्यकता है, लेकिन अक्सर हमारे ग्राफ में संग्रह आलसी शुरू नहीं होता है। आपने यह भी टिप्पणी की कि सत्र फ़ैक्टरी में @ आईडी के रीसेट करने की प्रक्रिया में सहायता करने के तरीके हैं। क्या आप कुछ कोड उदाहरण प्रदान कर सकते हैं, क्योंकि मुझे एक ही समस्या का सामना करना पड़ रहा है और यह मुझे पागल कर रहा है :) –

1

आप ऐसा क्यों करना चाहते हैं? यह हैकिंग की तरह थोड़ा लगता है।

कहा कि अपाचे कॉमन्स BeanUtils (उथले) वस्तु प्रतियां बनाने की cloneBean() और copyProperties() तरीकों में शामिल है। एक गहरी प्रतिलिपि बनाने के लिए आप प्रस्तावित here के रूप में एक विधि लिख सकते हैं।

+0

मैं डेटाबेस में संग्रहीत डेटा की गहरी प्रतियां बनाना चाहता हूं जो उस ऑब्जेक्ट से पूरी तरह स्वतंत्र हो जाएंगे जिसकी प्रतिलिपि बनाई गई थी। उदाहरण के लिए: -Object1 ऑब्जेक्ट 2 की एक गहरी प्रति है। -Object1 में एक बच्चा है (@OneToMany से) जो बदलता है। -Object2 के बच्चे को बदलने की जरूरत नहीं है। – User1

+2

गहरी कॉपी के लिए आप apache commons – rozky

3

मुझे सच में यकीन नहीं है कि पहले से प्रबंधित वस्तुओं की शून्यिंग आईडी एक अच्छा विचार है, esp। जब आपकी संस्थाओं में equals() आईडी की समानता के रूप में परिभाषित नहीं है। जेपीए कार्यान्वयन में कुछ कैश में प्रबंधित ऑब्जेक्ट्स हो सकते थे और ऑब्जेक्ट्स के आईडी के साथ खेलते समय बेस्कर जाते थे।

मुझे विश्वास है कि आरके के जवाब का पालन करना और वस्तुओं की असली प्रतिलिपि करना सुरक्षित होगा।

+0

से SerializationUtils.clone() का उपयोग कर सकते हैं। मैंने कुछ परियोजनाओं पर काम किया है जहां हमने ऑब्जेक्ट ग्राफ की गहरी प्रतिलिपि बनाने के लिए एक सामान्यीकृत तरीके से आने की कोशिश की। प्रोजेक्ट बढ़ने के साथ आप जिस समस्या को हमेशा चलाते हैं वह यह है कि आप ऑब्जेक्ट ग्राफ़ के विभिन्न हिस्सों को अलग-अलग उपयोग मामलों और/या ऑब्जेक्ट के भीतर गुणों के विभिन्न सेटों के लिए कॉपी करने की आवश्यकता को समाप्त करते हैं। आखिरकार, स्वचालित गहरे क्लोनिंग के साथ चालाक होने की कोशिश करने के बजाए तर्क को स्वयं लिखना आसान होता है। साथ ही, आईडी को मिटाने से लगभग निश्चित रूप से कुछ जेपीए कार्यान्वयन टूट जाएंगे। –

2

यदि आपकी ऑब्जेक्ट्स Serializable लागू करती हैं, तो आप एक गहरी प्रतिलिपि बनाने के लिए writeObject() और readObject() का उपयोग कर सकते हैं। हम एक आंकड़ा अंतरण वस्तु पदानुक्रम है और सार सुपर क्लास में इस विधि (डीटीओ) के माध्यम से गहरी प्रतियां समर्थन करते हैं:

/** 
* Reply a deep copy of this DTO. This generic method works for any DTO subclass: 
* 
*  Person person = new Person(); 
*  Person copy = person.deepCopy(); 
* 
* Note: Using Java serialization is easy, but can be expensive. Use with care. 
* 
* @return A deep copy of this DTO. 
*/ 
@SuppressWarnings("unchecked") 
public <T extends DTO> T deepCopy() 
{ 
    try 
    { 
     ObjectOutputStream oos = null; 
     ObjectInputStream ois = null; 
     try 
     { 
      ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
      oos = new ObjectOutputStream(bos); 
      oos.writeObject(this); 
      oos.flush(); 
      ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())); 
      return (T) ois.readObject(); 
     } 
     finally 
     { 
      oos.close(); 
      ois.close(); 
     } 
    } 
    catch (ClassNotFoundException cnfe) 
    { 
     // Impossible, since both sides deal in the same loaded classes. 
     return null; 
    } 
    catch (IOException ioe) 
    { 
     // This has to be "impossible", given that oos and ois wrap a *byte array*. 
     return null; 
    } 
} 

(। मुझे विश्वास है कि किसी को एक कारण है कि इन अपवादों हो सकता है मिलेगा हूँ)

अन्य धारावाहिक पुस्तकालय (उदाहरण के लिए, एक्सस्ट्रीम) का उपयोग उसी तरीके से किया जा सकता है।

+3

यह क्षणिक कीवर्ड के साथ चिह्नित फ़ील्ड की एक प्रति नहीं बनाएगा। –

+0

@ सेन: धन्यवाद, एक अच्छा बिंदु। (हमारे मामले में ये वेनिला जावाबीन्स हैं।) –

+2

@ सेन: चूंकि क्षणिक क्षेत्र डीबी में समाप्त नहीं होंगे, या तो, यह सही व्यवहार प्रतीत होता है। –

3

मैंने इसे हल किया।

मैंने एक घटक बनाया है जो पैकेज की टिप्पणियों (javax.persistence) के आधार पर आपके लिए यह पूरी प्रक्रिया बनाता है।

घटक पहले से ही इकाई की आईडी को शून्य में सेट करता है। वह प्रत्येक विशेषता संबंध @OneToMany, @OneToOne या @ManyToMany के प्रकार के आधार पर लागू होने के लिए एल्गोरिदम के सभी विश्लेषण करता है।

उदाहरण

Person person = personDAO.find(1); 
PersistenceCloner cloner = new PersistenceCloner(person); 
Person personCopy = cloner.generateCopyToPersist(); 

डाउनलोड जार और स्रोत: jpa-entitycloner