2011-01-18 17 views
11

मैं के रूप में (असंबंधित हटाया सामान) इस प्रकार दो इकाई सेम परिभाषित किया गया है:बंद हाइबरनेट से संग्रह को अद्यतन करने के लिए जब वे नहीं बदला है

@Entity 
@Table(...) 
public class MasterItem implements java.io.Serializable { 

    private Set<CriticalItems> criticalItemses = new HashSet<CriticalItems>(0); 

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "masterItem", orphanRemoval = true, 
      cascade = {javax.persistence.CascadeType.DETACH}) 
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE}) 
    public Set<CriticalItems> getCriticalItemses() { 
     return this.criticalItemses; 
    } 
} 

CriticalItems परिभाषित किया गया है इस प्रकार है:

@Entity 
@Table(...) 
public class CriticalItems implements java.io.Serializable { 

    private MasterItem masterItem; 

    @ManyToOne(fetch = FetchType.LAZY, optional = false, 
      cascade = {javax.persistence.CascadeType.DETACH}) 
    @Cascade({CascadeType.SAVE_UPDATE}) 
    @JoinColumn(name = "mi_item_id", nullable = false) 
    public MasterItem getMasterItem() { 
     return this.masterItem; 
    } 
} 

और मेरी

public MasterItem load(int id) { 
    MasterItem results = (MasterItem) getSessionFactory().getCurrentSession() 
     .get("com.xxx.MasterItem", id); 

} 

public void save(MasterItem master) { 
    // master has been changed by the UI since it 
    getSessionFactory().getCurrentSession().saveOrUpdate(master); 
} 

जब मैं एक MasterItem लोड करते हैं, इसे सही ढंग से लोड करता है, एक: - डीएओ कोड मैं इन तरीकों है डी निर्देशित के रूप में डेटा के साथ CriticalItems सेट भी लोड करता है। फिर, मैं यह डेटा अपने यूआई में भेजता हूं, और एक अपडेटेड कॉपी वापस प्राप्त करता हूं, जिसे मैं जारी रखने की कोशिश करता हूं। उपयोगकर्ता MasterItem ऑब्जेक्ट में फ़ील्ड्स अपडेट करता है, लेकिन इसमें क्रिटिकल इटम्स सेट या कुछ भी स्पर्श नहीं होता है - यह अनमोडिफाइड रहता है।

जब मेरी सेव() विधि लागू की जाती है, तो हाइबरनेट क्रिटिकल इटम्स के सेट में प्रत्येक आइटम के लिए एसक्यूएल अपडेट भेजने पर जोर दे रहा है, भले ही उनमें से कोई भी किसी भी तरह से बदल नहीं गया है।

कुछ खोदने के बाद, मुझे लगता है कि यह हो रहा है। जब मैं saveOrUpdate() करता हूं, तो हाइबरनेट मेरे मास्टरइटम ऑब्जेक्ट को अलग राज्य में देखता है, इसलिए यह डिस्क से इसे पुनः लोड करने का प्रयास करता है। हालांकि, ऐसा करने पर, ऐसा लगता है कि यह एक तैयार कथन का उपयोग कर रहा है (जिसे स्टार्ट-अप पर हाइबरनेट द्वारा स्वतः बनाया गया था) और यह तैयार कथन CriticalItems डेटा में शामिल होने का प्रयास नहीं करता है।

तो हाइबरनेट के पास मेरी अद्यतन मास्टरइटम ऑब्जेक्ट है जो क्रिटिकलइटम के पूर्ण सेट के साथ है, लेकिन बिना किसी संग्रह के मास्टरइटम का उपयोग "पिछली स्थिति" ऑब्जेक्ट के रूप में करता है। इस प्रकार, सभी CriticalItems एसक्यूएल के माध्यम से अद्यतन हो जाते हैं (डाला नहीं, जो खुद में दिलचस्प है)।

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

किसी भी अंतर्दृष्टि की सराहना की जाएगी।

अद्यतन: टिप्पणियों के आधार पर, मुझे लगता है कि मैं saveOrUpdate के बीच अंतर समझना() और विलय()। मुझे एहसास है कि saveOrUpdate() के परिणामस्वरूप सभी मामलों में एक SQL INSERT या SQL अद्यतन होगा, और सिद्धांत में, विलय, केवल तभी अपडेट जारी करेगा यदि ऑब्जेक्ट इसके लगातार राज्य से बदल गया है, लेकिन यह निर्धारित करने के लिए कि हाइबरनेट SQL SELECT के माध्यम से ऑब्जेक्ट को पहले लोड करना होगा।

तो, मैंने सोचा कि मैं बस अपने कोड में वापस जा सकता हूं और saveOrUpdate() को मर्ज करने के लिए बदल सकता हूं() और यह काम करेगा, लेकिन यह काफी मामला नहीं था।

जब मैं मर्ज(), मैं

org.springframework.orm.hibernate3.HibernateSystemException: could not initialize proxy - no Session; nested exception is org.hibernate.LazyInitializationException: could not initialize proxy - no Session 

हो रही थी थे, लेकिन यह ठीक काम किया है, तो मैं saveOrUpdate में वापस बदल दिया()।

मुझे अंत में पता चला कि क्यों - मैंने एनोटेशन (यूघ) में CascadeType.MERGE शामिल नहीं किया था। एक बार मैंने इसे ठीक कर लिया, अपवाद दूर चला गया।

+0

क्या आपके पास आशावादी लॉकिंग कॉलम है (एक कॉलम जिसे @ ओशन int के साथ @version के साथ एनोटेट किया गया है) – lweller

उत्तर

16

कि update() और merge() के बीच semantical अंतर है के लिए एक संशोधन स्तंभ (आशावादी ताला) जोड़ने के लिए प्रयास करें।

Christian Bauer and Gavin King's Java Persistence with Hibernate से (मैं हाइबरनेट डॉक्स में इस व्यवहार का स्पष्ट विवरण नहीं मिल सकता है):

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

दूसरी ओर, merge() पहले डेटाबेस से पूछताछ करता है, और अगर राज्य नहीं बदला जाता है तो अद्यतन नहीं करता है।

तो, अगर आप पहली बार डेटाबेस क्वेरी करने के लिए हाइबरनेट चाहते हैं, आप का उपयोग करने के merge() (हालांकि update() के डिफ़ॉल्ट व्यवहार को अपने संस्थाओं पर @org.hibernate.annotations.Entity(selectBeforeUpdate = true) specifing द्वारा ओवरराइड किया जा सकता है) की जरूरत है।

+0

बिल्कुल वही जो मैं खोज रहा था - धन्यवाद दस लाख! – Jay

+0

एफवाईआई - मैं [इस पोस्ट में आगे बढ़ता हूं जो मतभेदों को आगे बढ़ाता है] (http://stackoverflow.com/questions/170962/nhibernate-difference-between-session-merge-and-session-saveorupdate) अपडेट() या saveOrUpdate के बीच() और विलय()। – Jay

1

अपने संस्थाओं

@Version 
Date lastModified; 
+0

FYI - इससे मदद मिली हो सकती है, लेकिन मेरे डेटाबेस में संस्करण कॉलम नहीं हैं। – Jay