2010-10-21 6 views
15

मुझे पता है कि अनाथाश्रम बाल वस्तुओं को हटाना SO पर एक आम प्रश्न है और हाइबरनेट के लिए नए लोगों के लिए एक आम समस्या है, और यह कि मानक मानक उत्तर यह सुनिश्चित करना है कि आपके पास बाल संग्रह पर cascade=all,delete-orphan या cascade=all-delete-orphan की कुछ भिन्नता है।अलग वस्तु को अद्यतन करते समय अनाथ संग्रह को हटा सकते हैं?

मैं हाइबरनेट को यह पता लगाने में सक्षम होना चाहता हूं कि मूल संग्रह से बाल संग्रह खाली/हटा दिया गया है, और मूल ऑब्जेक्ट अपडेट होने पर डेटाबेस से हटाई गई बाल तालिका में पंक्तियां हैं। उदाहरण के लिए:

Parent parent = session.get(...); 
parent.getChildren().clear(); 
session.update(parent); 

Parent वर्ग के लिए मेरे वर्तमान मानचित्रण की तरह दिखता है:

<bag name="children" cascade="all-delete-orphan"> 
    <key column="parent_id" foreign-key="fk_parent_id"/> 
    <one-to-many class="Child"/> 
</bag> 

जब एक संलग्न वस्तु को अद्यतन करने के यह मेरे लिए ठीक काम करता है, लेकिन मैं एक का उपयोग मामला है जिसमें हम चाहते हैं एक पृथक ऑब्जेक्ट (जिसे HTTP/JSON पर रिमोट क्लाइंट द्वारा हमारे एपीआई विधि में भेजा गया है) ले जाने में सक्षम होने के लिए, और सीधे इसे हाइबरनेट सत्र में पास कर दें - ताकि ग्राहकों को मूल ऑब्जेक्ट में किसी भी तरह से हेरफेर करने में सक्षम बनाया जा सके। वे पसंद करते हैं और परिवर्तन जारी रहते हैं।

मेरी अलग वस्तु पर session.update(parent) पर कॉल करते समय, बच्चे की तालिका में पंक्तियां अनाथ हैं (एफके कॉलम शून्य पर सेट है) लेकिन हटाई नहीं गई है। ध्यान दें कि जब मैं session.update() पर कॉल कर रहा हूं, यह पहली बार है जब हाइबरनेट सत्र इस ऑब्जेक्ट इंस्टेंस को देख रहा है - मैं ऑब्जेक्ट को किसी अन्य तरीके से ऑब्जेक्ट के साथ फिर से अटैचमेंट या विलय नहीं कर रहा हूं। मैं उन ऑब्जेक्ट्स को पास करने के लिए क्लाइंट पर निर्भर हूं जिनकी पहचानकर्ता डेटाबेस में वास्तविक वस्तुओं से मेल खाते हैं।

String jsonString = request.getParameter(...); 
Parent parent = deserialize(jsonString); 
session.update(parent); 

यह जब session.update(parent) के लिए पारित हाइबरनेट अलग माता पिता वस्तुओं में अनाथ बच्चों के संग्रह का पता लगाने के लिए संभव है: उदाहरण के लिए, मेरी एपीआई सेवा विधि में तर्क कुछ इस तरह है? या क्या मैं किसी भी तरह से अलग वस्तु का गलत उपयोग कर रहा हूं?

मेरी आशा थी कि मैं एक अलग उदाहरण में परिवर्तनों को जारी रखने के लिए हाइबरनेट के साथ किसी भी तरह की जटिल बातचीत से बच सकता हूं। session.update(parent) पर कॉल के बाद मेरी एपीआई विधि को पृथक ऑब्जेक्ट को और संशोधित करने की आवश्यकता नहीं है, यह विधि केवल दूरस्थ क्लाइंट अनुप्रयोगों द्वारा किए गए परिवर्तनों के लिए ज़िम्मेदार है।

उत्तर

1

मुझे लगता है कि, अलग सत्र का उपयोग करते समय, आपको संग्रह के साथ समस्या का सामना करना पड़ सकता है। मैं आपको पहले इकाई को संग्रह के साथ लोड करने का सुझाव दूंगा, और उसके बाद उस इकाई को परिवर्तनों के साथ अपडेट करूँगा, जो मदद करेगा।

+0

तुम्हारा मतलब क्या देखते हैं, मौजूदा इकाई और उसके बाद 'मर्ज लोड () 'यह अलग प्रकरण के साथ मुझे एपीआई पास किया? –

+0

@ mattb: आप संग्रह को मर्ज करने के लिए एक तर्क लिख सकते हैं, या यहां तक ​​कि पिछले संग्रह को भी प्रतिस्थापित कर सकते हैं और नया सेट कर सकते हैं, लेकिन यह सुनिश्चित कर लें कि आपने अपने एचबीएम में टैग जोड़ा है। यह में एक नया सहेजने से पहले पूर्ण संग्रह को हटाने के लिए एक सरल एसक्यूएल डिलीट क्वेरी होगी। या अन्य तरीकों से, आप कुछ भी जोड़ देंगे, इस एसक्यूएल डिलीट को हर बार निकाल दिया जाएगा और फिर आपके संग्रह की ताजा प्रति जोड़ा जाएगा। यह मैन्युअल रूप से संग्रह को अद्यतन करने की हर समस्या की आपकी समस्या का समाधान कर सकता है। –

+0

मुझे यकीन नहीं है कि मुझे यह समाधान पसंद है, क्योंकि इसे मेरे उपयोग पैटर्न को बदलने की आवश्यकता होगी - उदाहरण के लिए ' 'जोड़ना। उम्मीद थी कि यह अकेले मैपिंग के साथ तय किया जा सकता है। –

8

आपका मानचित्रण (सरलीकृत)

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="br.com._3988215.model.domain"> 
    <class name="Parent" table="PARENT"> 
     <id name="id"> 
      <generator class="native"/> 
     </id> 
     <bag cascade="all,delete-orphan" name="childList"> 
      <key column="PARENT_ID" not-null="false"/> 
      <one-to-many class="Child"/> 
     </bag> 
    </class> 
    <class name="Child" table="CHILD"> 
     <id name="id" column="CHILD_ID"> 
      <generator class="native"/> 
     </id> 
    </class> 
</hibernate-mapping> 

पैदा करता

PARENT 
    ID 

CHILD 
    CHILD_ID 
    PARENT_ID 

अनुसार जो आपने कहा है

मैं हाइबरनेट के लिए है कि बच्चे संग्रह का पता लगाने में सक्षम होना चाहते हैं से हटा दिया गया है पैरेंट ऑब्जेक्ट, और बच्चे तालिका में पंक्तियों डेटाबेस जब जनक वस्तु अद्यतन किया जाता है

तरह
Parent parent = session.get(...); 
parent.getChildren().clear(); 

session.update(parent); 

आप ने कहा कि यह काम करता है ठीक क्योंकि आपके पास से नष्ट कर दिया है एक संलग्न अभिभावक उदाहरण

अब हम निम्नलिखित देखें (नोटिस Assert.assertNull (दूसरा))

public class WhatYouWantTest { 

    private static SessionFactory sessionFactory; 

    private Serializable parentId; 

    private Serializable firstId; 
    private Serializable secondId; 

    @BeforeClass 
    public static void setUpClass() { 
     Configuration c = new Configuration(); 
     c.addResource("mapping.hbm.3988215.xml"); 

     sessionFactory = c.configure().buildSessionFactory(); 
    } 

    @Before 
    public void setUp() throws Exception { 
     Parent parent = new Parent(); 
     Child first = new Child(); 
     Child second = new Child(); 

     Session session = sessionFactory.openSession(); 
     session.beginTransaction(); 

     parentId = session.save(parent); 
     firstId = session.save(first); 
     secondId = session.save(second); 

     parent.getChildList().add(first); 
     parent.getChildList().add(second); 

     session.getTransaction().commit(); 
     session.close(); 
    } 

    @Test 
    public void removed_second_from_parent_remove_second_from_database() { 
     Parent parent = new Parent(); 
     parent.setId((Integer) parentId); 

     Child first = new Child(); 
     first.setId((Integer) firstId); 

     /** 
      * It simulates the second one has been removed 
      */ 
     parent.getChildList().add(first); 

     Session session = sessionFactory.openSession(); 
     session.beginTransaction(); 

     session.update(parent); 

     session.getTransaction().commit(); 
     session.close(); 

     session = sessionFactory.openSession(); 
     session.beginTransaction(); 

     Child second = (Child) session.get(Child.class, secondId); 
     Assert.assertNull(second); 

     session.getTransaction().commit(); 
     session.close(); 
    } 
} 

दुर्भाग्य, टेस्ट पास नहीं है। आप क्या कर सकते है ???

  • एक लंबे समय से चल बातचीत सक्षम

हाइबरनेट संदर्भ कहते हैं

विस्तारित (या लांग) सत्र - हाइबरनेट सत्र अंतर्निहित JDBC कनेक्शन से काट दिया जा सकता है के बाद डेटाबेस लेन-देन हुआ प्रतिबद्ध किया गया है, और एक नया ग्राहक अनुरोध होता है जब पुन: कनेक्ट किया गया। इस पैटर्न को सत्र-प्रति-वार्तालाप के रूप में जाना जाता है और अनावश्यक को भी पुन: संसाधित करता है। स्वचालित संस्करण का उपयोग समवर्ती संशोधनों को अलग करने के लिए किया जाता है और सत्र को आमतौर पर स्वचालित रूप से फ़्लश करने की अनुमति नहीं दी जाती है, लेकिन स्पष्ट रूप से।

अस्वीकरण: मेरे पास कोई परिदृश्य नहीं है जो लंबे समय तक चलने वाली बातचीत का उपयोग करता है। जावा ईई स्टेटफुल सत्र सत्र लंबे समय तक चलने वाली बातचीत का समर्थन करते हैं। लेकिन इसका समर्थन जेपीए (हाइबरनेट नहीं)

या आप वैकल्पिक मैपिंग बना सकते हैं जो आपके बच्चे को समग्र तत्वों के रूप में सक्षम बनाता है।क्योंकि इसके जीवन चक्र पैरेंट ऑब्जेक्ट पर निर्भर करता है, तो आप आप क्या चाहते हैं

एक वर्ग AlternativeParent नामित जो समग्र तत्व के रूप में माता पिता फैली

public class AlternativeParent extends Parent {} 

अब अपने मानचित्रण (सूचना बाल बनाएं पाने के लिए समग्र तत्वों पर भरोसा कर सकते के बजाय सादे @Entity)

<class name="AlternativeParent" table="PARENT"> 
    <id name="id"> 
     <generator class="native"/> 
    </id> 
    <bag name="childList" table="CHILD"> 
     <key column="PARENT_ID" not-null="false"/> 
     <composite-element class="Child"> 
      <property column="CHILD_ID" name="id"/> 
     </composite-element> 
    </bag> 
</class> 

अब एक सुविधाजनक लागू बाल वर्ग में विधि के बराबर होती है

public boolean equals(Object o) { 
    if (!(o instanceof Child)) 
     return false; 

    Child other = (Child) o; 
    // identity equality 
    // Used by composite elements 
    if(getId() != null) { 
     return new EqualsBuilder() 
        .append(getId(), other.getId()) 
        .isEquals(); 
    } else { 
     // object equality 
    } 
} 

तो मैं परीक्षण का मामला ऊपर दिखाए गए (अब बजाय AlternativeParent का उपयोग करके)

@Test 
public void removed_second_from_parent_remove_second_from_database() { 
    AlternativeParent parent = new AlternativeParent(); 
    parent.setId((Integer) parentId); 

    Child first = new Child(); 
    first.setId((Integer) firstId); 

    /** 
     * It simulates the second one has been removed 
     */ 
    parent.getChildList().add(first); 

    Session session = sessionFactory.openSession(); 
    session.beginTransaction(); 

    session.update(parent); 

    session.getTransaction().commit(); 
    session.close(); 

    session = sessionFactory.openSession(); 
    session.beginTransaction(); 

    Child second = (Child) session.get(Child.class, secondId); 
    Assert.assertNull(second); 

    session.getTransaction().commit(); 
    session.close(); 

} 

refactor मैं हरे रंग का बार

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