2008-10-07 25 views
20

मेरे ऐप में मेरे पास इन हाइबरनेट-मैप किए गए प्रकार (सामान्य मामले) हैं:जब मैं अद्यतन/सम्मिलित करने का प्रयास करता हूं तो हाइबरनेट को हटाने का प्रयास क्यों करता है?

class RoleRule { 
    private Role role; 
    private PermissionAwareEntity entity; // hibernate-mapped entity for which permission is granted 
    private PermissionType permissionType; // enum 

    @ManyToOne 
    @JoinColumn(name = "ROLE_ID") 
    public Role getRole() { 
    return role; 
    } 
    public void setRole(Role role) { 
    this.role = role; 
    } 

} 

class Role { 
    private Set<RoleRule> rules = new HashSet<RoleRule>(0); 

    @OneToMany(cascade=CascadeType.ALL) 
    @JoinColumn(name="ROLE_ID") 
    public Set<RoleRule> getRules() { 
    return rules; 
    } 
    public void setRules(Set<RoleRule> rules) { 
    this.rules = rules; 
    } 

} 

सभी वर्गों में equals() & hashCode() ओवरराइड हैं।

मेरा एप्लिकेशन भूमिकाओं के tweaking (केवल sysadmins द्वारा, चिंता मत करो), और अन्य क्षेत्रों के बीच, नए भूमिका नियमों के निर्माण की अनुमति देता है। जब कोई नया नियम बनाया जाता है तो मैं एक नया RoleRule ऑब्जेक्ट बनाने की कोशिश करता हूं और इसे भूमिका के क्षेत्र rules में डालता हूं। मैं डेटाबेस में परिवर्तन लागू करने के लिए session.update(role) पर कॉल करता हूं।

अब बदसूरत हिस्सा आता है ... हाइबरनेट लेनदेन को बंद करते समय निम्नलिखित करने का निर्णय लेता है और flushing:

  1. डेटाबेस में नया नियम डालें। अति उत्कृष्ट।
  2. अन्य भूमिका फ़ील्ड अपडेट करें (संग्रह नहीं)। अब तक सब ठीक है।
  3. मौजूदा नियमों को अद्यतन करें, भले ही उनमें कुछ भी नहीं बदला है। मैं इसके साथ रह सकता हूँ।
  4. मौजूदा नियम फिर अद्यतन करें। स्वचालित टिप्पणी सहित लॉग से पेस्ट यहां दिया गया है:
/* delete one-to-many row Role.rules */ 
update ROLE_RULE set ROLE_ID=null where ROLE_ID=? and ROLE_RULE_ID=?

बेशक, सभी फ़ील्ड शून्य नहीं हैं, और यह ऑपरेशन शानदार रूप से विफल रहता है।

क्या कोई यह बताने की कोशिश कर सकता है कि हाइबरनेट ऐसा क्यों करेगा ??? और इससे भी महत्वपूर्ण बात यह है कि मैं इस तरह के फ्रेक कैसे प्राप्त करता हूं ???

edit: मुझे यकीन था कि यह मैपिंग के साथ कुछ करने के लिए था, और फिर मेरे मालिक, एक सनकी पर, दोनों वर्गों में equals() और hashCode() हटा दिया, ग्रहण का उपयोग करके उन्हें फिर से बनाया, और रहस्यमय रूप से इस समस्या को हल किया ।

मैं अभी भी अपने प्रश्न के बारे में बहुत उत्सुक हूं। क्या कोई सुझाव दे सकता है कि हाइबरनेट ऐसा क्यों करेगा?

+0

आप किस ड्राइवर और बोली का उपयोग कर रहे हैं? –

+0

एप्लिकेशन ओरेकल 10 जी पर चल रहा है, लेकिन इससे कोई फर्क नहीं पड़ता। – Yuval

+0

सबसे महत्वपूर्ण बात यह है कि 'बराबर' और 'हैशकोड' विधियों के कार्यान्वयन आपकी पोस्ट से गायब हैं। डेटाबेस पहचान मानों के आधार पर आपके 'बराबर' और 'हैशकोड' विधियों का निर्माण ** हाइबरनेट या आपके डेटाबेस द्वारा उत्पन्न ** एक बुरा विचार है, जिससे उन्हें किसी भी क्षेत्र पर निर्भर किया जा सकता है जिसे निर्माण के समय के बाद अद्यतन किया जा सकता है। –

उत्तर

3

मुझे यकीन है कि अगर यह समाधान है नहीं कर रहा हूँ, लेकिन आप कोशिश करना चाहते हो सकता है:

@OneToMany(mappedBy = "role") 

और @JoinColumn एनोटेशन नहीं? मुझे लगता है कि दोनों संस्थाएं एसोसिएशन को 'खुद' करने की कोशिश कर रही हैं, यही कारण है कि एसक्यूएल गड़बड़ हो सकता है?

@Entity 
@org.hibernate.annotations.Entity(
    dynamicInsert = true, dynamicUpdate = true 
) 
7

मैं आम तौर पर एक संग्रह को अद्यतन करने के दो तरीके का उपयोग किया है (कई:

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

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

copy the list of existing records to a list_to_delete 
for each record from the form 
    remove it from the list_to_delete 
    if the record exists (based on equals()? key?) 
    change each field that the user can enter 
    else if the record doesn't exist 
    add it to the collection 
end for 
for each list_to_delete 
    remove it 
end for 
save 

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

+2

क्या यह अभी भी एकमात्र समाधान है? मैंने सोचा कि हाइबरनेट का पूरा बिंदु प्रत्येक ऑब्जेक्ट के लिए व्यक्तिगत रूप से कोड करने से बचने के लिए था, और कोड को बनाए रखने में आसान बना दिया गया था। क्या प्रत्येक ऑब्जेक्ट के लिए कोई विधि लिखने के बिना ऐसा करने का कोई तरीका है, उदाहरण के लिए एक हाइबरनेट विकल्प जिसे सेट करने की आवश्यकता है? – pete

4

प्रश्न 'Overriding equals and hashCode in Java' का उत्तर देखें।

यह समझाता है कि बराबर और हैशकोड विधियों को ओवरराइड करने के लिए, जो आपकी समस्या है क्योंकि यह उन्हें फिर से लिखने के बाद काम करता था।

गलत तरीके से ओवरराइड करने से आपके संग्रह को हटाने और उन्हें पुन: सम्मिलित करने के लिए हाइबरनेट का नेतृत्व किया जा सकता है। (हैश कुंजी को मानचित्रों में चाबियों के रूप में उपयोग किया जाता है)

+4

मैं बराबर और हैशकोड के महत्व, और उन्हें ओवरराइड करने के महत्व के बारे में अच्छी तरह से अवगत हूं। यहां पर महान रहस्य यह है कि पुराने बराबर + हैशकोड नए जेनरेट के समान हैं ... और फिर भी यह मेरी समस्या का समाधान करता है। क्या आप इसे समझा सकते हैं? – Yuval

0

ब्रायन डिटरलिंग के उत्तर ने मुझे प्रेत हटाने को दूर करने में मदद की। काश वह एक असली कोड डाल दिया था। यहां बताया गया है कि मुझे उनके सुझाव से क्या मिला 1. किसी के लिए इसका इस्तेमाल करने या मेरे कोड पर टिप्पणी करने के लिए पोस्ट करना।

// snFile and task share many to many relationship 

@PersistenceContext 
private EntityManager em; 

public SnFile merge(SnFile snFile) { 
     log.debug("Request to merge SnFile : {}", snFile); 

     Set<Task> tasks = taskService.findBySnFilesId(snFile.getId()); 
     if(snFile.getTasks() != null) { 
      snFile.getTasks().clear(); 
     } 
     em.merge(snFile); 
     em.flush(); 
     if(tasks != null) { 
      if(snFile.getTasks() != null) 
       snFile.getTasks().addAll(tasks); 
      else 
       snFile.setTasks(tasks); 
     } 

     return em.merge(snFile); 
    } 
संबंधित मुद्दे

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