2012-09-10 33 views
5

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

हाइबरनेट: sst.level_1 में डालने (स्थिति, नाम) मान हाइबरनेट (,?): CATEGORY4_ के रूप में चयन level2x_.LEVEL_1_ID, level2x_.TIMESEGMENT, level2x_.CATEGORY sst.level_2 level2x_ जहां level2x_.LEVEL_1_ID = से? और level2x_.TIMESEGMENT =?

एपीआई हाइबरनेट 4.1.6/वसंत 3.1.2 हैं।

CREATE TABLE level_1 
(
ID int NOT NULL PRIMARY KEY AUTO_INCREMENT, 
STATUS int, 
NAME varchar(255) 
); 

CREATE TABLE level_2 
(
LEVEL_1_ID int, 
TIMESEGMENT int, 
CATEGORY varchar(2), 
PRIMARY KEY (LEVEL_1_ID, TIMESEGMENT), 
FOREIGN KEY (LEVEL_1_ID) REFERENCES level_1(ID) ON DELETE CASCADE 
); 

यहाँ परीक्षण कोड है:

यहाँ MySQL के लिए तालिका परिभाषा है। Level1 के लिए

public class Test { 

    public static void main(String[] args) { 
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 
     doInsert(context); 
    } 

    private static void doInsert(ApplicationContext context) { 

     Level1 level1 = new Level1(); 
     Level2 level2 = new Level2(); 

     level1.setName("LEVEL 1 NAME"); 
     level1.setStatus(1); 
     level1.getLevel2s().add(level2); 

     level2.setLevel1(level1); 
     level2.setCategory("CA"); 
     level2.setId(new Level2Id(level1.getId(), 10)); 

     Level1DAO level1DAO = (Level1DAO) context.getBean("Level1DAO"); 
     level1DAO.save(level1); 
    } 
} 

मैपिंग: Level2 के लिए

<hibernate-mapping> 
    <class name="com.jc.hibernate.Level1" table="level_1" catalog="sst"> 
     <id name="id" type="java.lang.Integer"> 
      <column name="ID" /> 
      <generator class="identity" /> 
     </id> 
     <property name="status" type="java.lang.Integer"> 
      <column name="STATUS" /> 
     </property> 
     <property name="name" type="java.lang.String"> 
      <column name="NAME" /> 
     </property> 
     <set name="level2s" inverse="true" cascade="all"> 
      <key> 
       <column name="LEVEL_1_ID" not-null="true" /> 
      </key> 
      <one-to-many class="com.jc.hibernate.Level2" /> 
     </set> 
    </class> 
</hibernate-mapping> 

मैपिंग:

<hibernate-mapping> 
    <class name="com.jc.hibernate.Level2" table="level_2" catalog="sst"> 
     <composite-id name="id" class="com.jc.hibernate.Level2Id"> 
      <key-property name="level1Id" type="java.lang.Integer"> 
       <column name="LEVEL_1_ID" /> 
      </key-property> 
      <key-property name="timesegment" type="java.lang.Integer"> 
       <column name="TIMESEGMENT" /> 
      </key-property> 
     </composite-id> 
     <many-to-one name="level1" class="com.jc.hibernate.Level1" update="false" insert="false" fetch="select"> 
      <column name="LEVEL_1_ID" not-null="true" /> 
     </many-to-one> 
     <property name="category" type="java.lang.String"> 
      <column name="CATEGORY" length="2" /> 
     </property> 
    </class> 
</hibernate-mapping> 

उत्तर

1

आपका मानचित्रण सही हो रहा है।

आपकी समस्या लग रहा है लाइन

level2.setId(new Level2Id(level1.getId(), 10)); 

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

Integer generatedId = (Integer) Session.save(level1) 

इस डेटाबेस में एक तत्काल डालने करता है और पहचानकर्ता रिटर्न क्या करने की जरूरत होगी। तो फिर तुम Lever2Id

level2.setId(new Level2Id(generatedId , 10)); 

मैं मैपिंग आपके द्वारा दी गई और उसके काम कर जुर्माने के साथ MySql पर इस कोशिश की बनाने के लिए पहचानकर्ता का उपयोग कर सकते हैं।

मैं पहली बार बचाने नहीं है, तो level1 पहले, यह मेरे त्रुटि देता है

Column 'LEVEL_1_ID' cannot be null 

अद्यतन

दुर्भाग्य से यह झरना की तरह दिखता है काम नहीं करता है स्वचालित रूप से जब वहाँ संयुक्त चाबियाँ हैं बच्चे में और समग्र कुंजी में कॉलम में से एक माता-पिता की प्राथमिक कुंजी को संदर्भित करता है। तो आपको ऊपर दिखाए गए अनुसार आईडी और रिश्ते मैन्युअल रूप से सेट करना होगा।

ध्यान दें कि अगर बच्चे के पास एक कॉलम आईडी है और आपका संबंध एक से एक है तो हाइबरनेट यह पता लगा सकता है कि बच्चा प्राथमिक कॉलम माता-पिता से आता है और स्वचालित रूप से सेट हो सकता है।भी सुझाव है कि यह here

"आप एक IdentifierGenerator उपयोग नहीं कर सकते समग्र कुंजी उत्पन्न करने के लिए here और here

दस्तावेज़ देख सकेंगे। इसके बजाय अनुप्रयोग की अपनी पहचानकर्ता सौंपना होगा। "

हाइबरनेट वर्ग समग्र आईडी मानचित्रण का प्रतिनिधित्व org.hibernate.mapping.Component (जो घटक, समग्र तत्व, समग्र पहचानकर्ता, आदि के लिए प्रयोग किया जाता है) और डिफ़ॉल्ट है आईडी पीढ़ी की रणनीति "असाइन की गई है" जब तक कि आपने एक कस्टम आईडी जनरेटर प्रदान नहीं किया है जो आपको अपने स्वयं के कंपोजिट यूज़र टाइप (समग्र आईडी के लिए) बनाकर हैकिश तरीके से ले जाता है और here के अनुसार कस्टम आइडेंटिफ़ायर जनरेटर का उपयोग करता है। लेकिन यह बदसूरत और एक overkill लग रहा है।

दोनों माता पिता और बच्चे को बचाने और एक सौदे में मैन्युअल रूप से संबंध स्थापित करने के पहले अपने जनक सेट तत्व से झरना सभी विकल्प निकाल या इसे करने के लिए "कोई नहीं" निर्धारित करते हैं, ताकि हाइबरनेट से कोई सकर्मक हठ है के बारे में

। माता-पिता को सहेजने से केवल माता-पिता को बचाया जाएगा, न कि बच्चे।

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

Parent parent = new Parent(); 
    parent.setStatus(1 ); 
    parent.setName("Parent"); 
    ChildId childId = new ChildId();  
    Child child = new Child(childId);  
    child.setCategory("TH");  
    parent.addChild(child); 
    child.getId().setTimesegment(10); 

लिए अभिभावकों की addChild विधि के साथ-साथ सेट संग्रह करने के लिए बच्चे को कहते हैं एक सुविधाजनक तरीका में बच्चे माता-पिता

public void addChild(Child child){ 
    if (child !=null){ 
     getChildrens().add(child); 
     child.setParent(this); 
    } 

    } 

फिर डीएओ में एक तरीका है जिसके पैरामीटर के रूप में बाल लेता है करने के लिए है और यह भी व्यवहार है, कुछ इस तरह

public void save(Child child){ 

    //get Session 
    Session session =....... 
    Transaction tx = session.beginTransaction(); 
    Integer generatedId = (Integer)session.save(child.getParent()); 
    ChildId childId = child.getId(); 
    childId.setChildId(generatedId);  
    session1.save(child); 
    tx1.commit(); 
    HibernateUtil.closeSession(); 
} 

की अब इस मैं क्या कर सकते हैं सुझाव है (हालांकि बेहतर तरीका डीएओ परत के बजाय सेवा परत व्यवहार बनाने के लिए है)।

+0

उत्तर के लिए धन्यवाद। यह समझ में आता है कि स्तर 1 आईडी शून्य है, जिससे समस्या उत्पन्न हुई। इस मामले में, मैं स्तर 1 और 2 के लिए परमाणु बनाने के लिए लेनदेन को कैसे कॉन्फ़िगर करूँगा? – John

+0

लेनदेन में बच्चे और माता-पिता दोनों को बचाने के लिए मेरे अपडेट देखें – Shailendra

0

बस अपडेट करने के लिए। मैंने समग्र आईडी हटा दी। इसके बजाय, बाल तालिका पर डेटाबेस जेनरेट की गई सरोगेट कुंजी का उपयोग करें, और पैरेंट आईडी पर एक विदेशी कुंजी का उपयोग करें। यह कैस्केड = "सब" के साथ कई संबंधों के साथ काम करता है। बचाना माता-पिता एक कदम में बच्चे को बचाता है। यह मूल प्रश्न, लेकिन एक विकल्प हल नहीं करता है।

CREATE TABLE level_11 (
ID int NOT NULL PRIMARY KEY AUTO_INCREMENT, 
STATUS int, NAME varchar(255)); 

CREATE TABLE level_22 (ID int NOT NULL PRIMARY KEY AUTO_INCREMENT, 
LEVEL_11_ID int NOT NULL, 
TIMESEGMENT int NOT NULL, 
FOREIGN KEY (LEVEL_11_ID) REFERENCES level_11(ID) ON DELETE CASCADE, 
CONSTRAINT UQ_LEVEL2 UNIQUE (LEVEL_11_ID, TIMESEGMENT));