2009-03-23 7 views
27

मुझे अभी पता चला है कि अगर मुझे एनएचबीर्नेट सत्र से ऑब्जेक्ट मिलता है और ऑब्जेक्ट पर कोई संपत्ति बदलती है, तो एनएचबीर्नेट स्वचालित रूप से Session.Update(myObj) पर कॉल किए बिना ऑब्जेक्ट को निष्क्रिय कर देगा!NHibernate की स्वचालित (गंदे जांच) अद्यतन व्यवहार को कैसे बंद करें?

मैं देख सकता हूं कि यह कैसे उपयोगी हो सकता है, लेकिन डिफ़ॉल्ट व्यवहार के रूप में यह पागल लगता है!

अद्यतन: अब मैं दृढ़ता अज्ञानता को समझता हूं, इसलिए यह व्यवहार अब स्पष्ट रूप से पसंदीदा विकल्प है। आशा है कि अन्य प्रोफेसर उपयोगकर्ताओं की आशा रखने के लिए मैं अब यह शर्मनाक प्रश्न छोड़ दूंगा।

मैं यह कैसे रोक सकता हूं? क्या यह डिफ़ॉल्ट NHibernate व्यवहार या Fluent NHibernate के AutoPersistenceModel से कुछ आ रहा है?

यदि इसे रोकने का कोई तरीका नहीं है, तो मैं क्या करूँ? जब तक मैं इस बिंदु को याद नहीं कर रहा हूं, यह व्यवहार सही गड़बड़ पैदा करता है।

मैं NHibernate 2.0.1.4 और एक धाराप्रवाह NHibernate से 18/3/2009

निर्माण का उपयोग कर रहा सही his answer साथ इस आदमी है?

मैंने यह भी पढ़ा है कि एक ईवेंट श्रोता को ओवरराइड करना इसका समाधान हो सकता है। हालांकि, इस स्थिति में IDirtyCheckEventListener.OnDirtyCheck नहीं कहा जाता है। क्या किसी को पता है कि मुझे कौन सा श्रोता ओवरराइड करने की ज़रूरत है?

उत्तर

13

आप Session.FlushMode से FlushMode.Never पर सेट कर सकते हैं। इससे आपके परिचालन स्पष्ट हो जाएंगे

यानी: tx.Commit() या session.Flush() पर। बेशक यह अभी भी प्रतिबद्ध/फ्लश पर डेटाबेस अद्यतन करेगा। यदि आप यह व्यवहार नहीं चाहते हैं, तो session.Evict(yourObj) पर कॉल करें और फिर यह क्षणिक हो जाएगा और NHibernate इसके लिए किसी भी डीबी कमांड जारी नहीं करेगा।

आपके संपादन का जवाब: हाँ, वह लड़का आपको इसे नियंत्रित करने के तरीके पर अधिक विकल्प देता है।

+1

हाँ, लेकिन जब भी मैं फ्लश करता हूं तब भी यह तब भी होगा। –

+0

आह, फिर सत्र करके ऑब्जेक्ट क्षणिक बनाओ। एक्टिक्ट() –

+0

मुझे लगता है कि मुझे लगता है कि निबर्ननेट मुझे मैन्युअल रूप से अद्यतनों को नियंत्रित नहीं करना चाहता, ये सभी समाधान हैक की तरह लगते हैं। यह क्यों है? –

1

SaveOrUpdate() या Save() को कॉल करना एक ऑब्जेक्ट लगातार बना देता है। यदि आपने इसे एक ISession या लगातार ऑब्जेक्ट के संदर्भ से पुनर्प्राप्त कर लिया है, तो ऑब्जेक्ट लगातार है और सत्र को फ़्लश करने से परिवर्तनों को बचाया जाएगा। आप ऑब्जेक्ट() को ऑब्जेक्ट पर कॉल करके इस व्यवहार को रोक सकते हैं जो इसे क्षणिक बनाता है।

जोड़ने के लिए संपादित: मैं आम तौर पर काम की इकाई होने के लिए एक ISession मानता हूं। यह आसानी से एक वेब ऐप में लागू किया जाता है। सत्र-प्रति-अनुरोध का उपयोग करके, WinForms में अधिक नियंत्रण की आवश्यकता है।

+0

जब मैं बेदखल करता हूं, क्या मैं ऑब्जेक्ट पर मैन्युअल रूप से अपडेट कर सकता हूं? क्या यह पूरा दृष्टिकोण एक अच्छा विचार है? क्या सभी वस्तुओं के लिए यह डिफ़ॉल्ट व्यवहार करने का कोई तरीका है या क्या मुझे प्रत्येक को बेदखल करना है? –

+0

आपके द्वारा बेदखल करने के बाद, वस्तु क्षणिक है। इसे फिर से बनाने के लिए, आप उस पर SaveOrUpdate को कॉल कर सकते हैं। –

+0

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

3

मेरे समाधान:

  1. अपने प्रारंभिक ISession निर्माण में, (कहीं अपने इंजेक्शन ढांचे पंजीकरण के अंदर) सच करने के लिए DefaultReadOnly निर्धारित किया है।
  2. आपके आईरिपोजिटरी कार्यान्वयन में जो एनएचबेर्नेट के आसपास लपेटता है और आईएसशन और ऐसे में, इन्सर्ट, अपडेट, सम्मिलित करें और हटाएं (या इसी तरह) विधियों को प्रबंधित करता है जो ISession.Save, Update, SaveUpdate, आदि को कॉल करते हैं, केवल इकाई के लिए SetRead को कॉल करें और ध्वज झूठ पर सेट।
+0

धन्यवाद, आप मेरा दिन बचाओ! –

0

हमने एनएच के साथ इवेंट श्रोताओं का उपयोग करके ऐसा किया (यह मेरा काम नहीं है - लेकिन मुझे यह लिंक नहीं मिला है कि मैंने इसे कहाँ किया ...)।और फिर सहेजें (और SaveOrUpdate) के लिए उन्हें एक के रूप में स्थापित करने के लिए भरी हुई है, इसलिए कि वस्तु बना रहेगा जब हम स्वयं उस पर Save() कहते हैं -

हम जब डेटा में पढ़ना, केवल पठनीय के रूप में सेट करने के लिए एक EventListener है ।

वह - या आप एक IStatelessSession का उपयोग कर सकते हैं जिसमें कोई राज्य/चेंजट्रैकिंग नहीं है।

यह इकाई/आइटम को तुरंत लोड होने पर तुरंत पढ़ने के रूप में सेट करता है।

मैंने केवल एक सम्मिलन ईवेंट श्रोता शामिल किया है, लेकिन मेरा कॉन्फ़िगरेशन कोड उन सभी का संदर्भ देता है।

/// <summary> 
/// A listener that once an object is loaded will change it's status to ReadOnly so that 
/// it will not be automatically saved by NH 
/// </summary> 
/// <remarks> 
/// For this object to then be saved, the SaveUpdateEventListener is to be used. 
/// </remarks> 
public class PostLoadEventListener : IPostLoadEventListener 
{ 
    public void OnPostLoad(PostLoadEvent @event) 
    { 
     EntityEntry entry = @event.Session.PersistenceContext.GetEntry(@event.Entity); 

     entry.BackSetStatus(Status.ReadOnly); 
    } 
} 

वस्तु बचत पर, हम इस फोन लोडेड है कि वस्तु स्थापित करने के लिए (अर्थात यह अब बना रहेगा)

public class SaveUpdateEventListener : ISaveOrUpdateEventListener 
{ 
    public static readonly CascadingAction ResetReadOnly = new ResetReadOnlyCascadeAction(); 

    /// <summary> 
    /// Changes the status of any loaded item to ReadOnly. 
    /// </summary> 
    /// <remarks> 
    /// Changes the status of all loaded entities, so that NH will no longer TrackChanges on them. 
    /// </remarks> 
    public void OnSaveOrUpdate(SaveOrUpdateEvent @event) 
    { 
     var session = @event.Session; 
     EntityEntry entry = session.PersistenceContext.GetEntry(@event.Entity); 

     if (entry != null && entry.Persister.IsMutable && entry.Status == Status.ReadOnly) 
     { 
      entry.BackSetStatus(Status.Loaded); 
      CascadeOnUpdate(@event, entry.Persister, @event.Entry); 
     } 
    } 

    private static void CascadeOnUpdate(SaveOrUpdateEvent @event, IEntityPersister entityPersister, 
     object entityEntry) 
    { 
     IEventSource source = @event.Session; 
     source.PersistenceContext.IncrementCascadeLevel(); 
     try 
     { 
      new Cascade(ResetReadOnly, CascadePoint.BeforeFlush, source).CascadeOn(entityPersister, entityEntry); 
     } 
     finally 
     { 
      source.PersistenceContext.DecrementCascadeLevel(); 
     } 
    } 
} 

और हम इस प्रकार तो राष्ट्रीय राजमार्ग में इसे लागू:

public static ISessionFactory CreateSessionFactory(IPersistenceConfigurer dbConfig, Action<MappingConfiguration> mappingConfig, bool enabledChangeTracking,bool enabledAuditing, int queryTimeout) 
    { 
     return Fluently.Configure() 
      .Database(dbConfig) 
      .Mappings(mappingConfig) 
      .Mappings(x => x.FluentMappings.AddFromAssemblyOf<__AuditEntity>()) 
      .ExposeConfiguration(x => Configure(x, enabledChangeTracking, enabledAuditing,queryTimeout)) 
      .BuildSessionFactory(); 
    } 

    /// <summary> 
    /// Configures the specified config. 
    /// </summary> 
    /// <param name="config">The config.</param> 
    /// <param name="enableChangeTracking">if set to <c>true</c> [enable change tracking].</param> 
    /// <param name="queryTimeOut">The query time out in minutes.</param> 
    private static void Configure(NHibernate.Cfg.Configuration config, bool enableChangeTracking, bool enableAuditing, int queryTimeOut) 
    { 
     config.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "none"); 
     if (queryTimeOut > 0) 
     { 
      config.SetProperty("command_timeout", (TimeSpan.FromMinutes(queryTimeOut).TotalSeconds).ToString()); 
     } 

     if (!enableChangeTracking) 
     { 
      config.AppendListeners(NHibernate.Event.ListenerType.PostLoad, new[] { new Enact.Core.DB.NHib.Listeners.PostLoadEventListener() }); 
      config.AppendListeners(NHibernate.Event.ListenerType.SaveUpdate, new[] { new Enact.Core.DB.NHib.Listeners.SaveUpdateEventListener() }); 
      config.AppendListeners(NHibernate.Event.ListenerType.PostUpdate, new[] { new Enact.Core.DB.NHib.Listeners.PostUpdateEventListener() }); 
      config.AppendListeners(NHibernate.Event.ListenerType.PostInsert, new[] { new Enact.Core.DB.NHib.Listeners.PostInsertEventListener() }); 
     } 
    } 
+0

क्या आप हमें बता सकते हैं कि आपने ऐसा करने का फैसला क्यों किया है? क्या आपने प्रदर्शन में कुछ लाभ देखा? – yeska

+0

हमने कुछ बार डेटा मॉडल अपडेट कर रहे थे, लेकिन यह सुनिश्चित नहीं था कि हम उन्हें सहेजना चाहते हैं (मुझे लगता है - यह 2 साल पहले था)। संभवतः खराब आर्क, क्योंकि आपको केवल वही बदलना चाहिए जो आप सहेजना चाहते हैं। ट्रैकिंग बंद करना * सैद्धांतिक रूप से प्रदर्शन में सुधार करना चाहिए - लेकिन फिर आपको सबकुछ मैन्युअल रूप से सहेजना होगा। –

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