2008-11-13 12 views
30

के लोड हो रहा है किसी को भी nHibernate के साथ JSON.NET का उपयोग कर रहा है? मुझे लगता है कि जब मैं बाल संग्रह के साथ कक्षा लोड करने का प्रयास करता हूं तो मुझे त्रुटियां मिल रही हैं।JSON.NET और nHibernate लेज़ी संग्रह

+2

क्या आप कृपया जो त्रुटियां देख रहे हैं, उनके बारे में विवरण पोस्ट कर सकते हैं? –

+0

मुझे 'विधि या संचालन लागू नहीं किया जा रहा था।' और Liedman के फिक्स मेरे लिए काम किया। –

उत्तर

3

आप एक परिपत्र dependancy त्रुटि हो रही है? आप serialization से वस्तुओं को नजरअंदाज कैसे करते हैं?

के बाद से आलसी लोड हो रहा है एक प्रॉक्सी-वस्तुओं उत्पन्न करता है, किसी भी अपने वर्ग के सदस्यों को खो जाएँगे जिम्मेदार बताते हैं। मैं न्यूटॉन्सॉफ्ट JSON-serializer के साथ एक ही मुद्दे में भाग गया, क्योंकि प्रॉक्सी-ऑब्जेक्ट में [JsonIgnore] विशेषताएँ नहीं थीं।

+0

मेरा और हैंडक्रफ्टमैन के उत्तरों देखें, उनमें बिल्कुल इस समस्या का समाधान है। – Liedman

+2

नीचे दिए गए जवाब को रोकने के लिए आपके उत्तर से 1,5 साल पहले लिखा गया था? – jishi

+0

हां यह वही समस्या है जिसमें मैं चल रहा था। जब मैं त्रुटियों को प्राप्त कर रहा था तब मैं serialization से किसी भी वस्तु को अनदेखा नहीं कर रहा था। मुझे लगता है कि मुझे वापस जाने और दस्तावेज़ों को ठीक से पढ़ने की जरूरत है! – user32326

3

आप शायद उत्सुक वस्तु का सबसे लोड करना चाहते हैं इतना है कि यह धारावाहिक जा सकता है:

 ICriteria ic = _session.CreateCriteria(typeof(Person)); 

     ic.Add(Restrictions.Eq("Id", id)); 

     if (fetchEager) 
     { 
      ic.SetFetchMode("Person", FetchMode.Eager); 
     } 

ऐसा करने का एक अच्छा तरीका निर्माता के लिए एक bool जोड़ना है (bool isFetchEager) अपने डेटा का प्रदाता विधि।

18

मैं Json.NET साथ NHibernate का उपयोग और पाया है कि मैं अकथनीय "__interceptors" मेरे धारावाहिक वस्तुओं में गुण हो रही थी। ली हेन्सन द्वारा एक Google खोज this excellent solution चालू हुई जिसे मैंने जेसन.नेट 3.5 रिलीज 5 के साथ काम करने के लिए अनुकूलित किया।

public class NHibernateContractResolver : DefaultContractResolver 
{ 
    private static readonly MemberInfo[] NHibernateProxyInterfaceMembers = typeof(INHibernateProxy).GetMembers(); 

    protected override List<MemberInfo> GetSerializableMembers(Type objectType) 
    { 
    var members = base.GetSerializableMembers(objectType); 

    members.RemoveAll(memberInfo => 
         (IsMemberPartOfNHibernateProxyInterface(memberInfo)) || 
         (IsMemberDynamicProxyMixin(memberInfo)) || 
         (IsMemberMarkedWithIgnoreAttribute(memberInfo, objectType)) || 
         (IsMemberInheritedFromProxySuperclass(memberInfo, objectType))); 

    var actualMemberInfos = new List<MemberInfo>(); 

    foreach (var memberInfo in members) 
    { 
     var infos = memberInfo.DeclaringType.BaseType.GetMember(memberInfo.Name); 
     actualMemberInfos.Add(infos.Length == 0 ? memberInfo : infos[0]); 
    } 

    return actualMemberInfos; 
    } 

    private static bool IsMemberDynamicProxyMixin(MemberInfo memberInfo) 
    { 
    return memberInfo.Name == "__interceptors"; 
    } 

    private static bool IsMemberInheritedFromProxySuperclass(MemberInfo memberInfo, Type objectType) 
    { 
    return memberInfo.DeclaringType.Assembly == typeof(INHibernateProxy).Assembly; 
    } 

    private static bool IsMemberMarkedWithIgnoreAttribute(MemberInfo memberInfo, Type objectType) 
    { 
    var infos = typeof(INHibernateProxy).IsAssignableFrom(objectType) 
        ? objectType.BaseType.GetMember(memberInfo.Name) 
        : objectType.GetMember(memberInfo.Name); 

    return infos[0].GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length > 0; 
    } 

    private static bool IsMemberPartOfNHibernateProxyInterface(MemberInfo memberInfo) 
    { 
    return Array.Exists(NHibernateProxyInterfaceMembers, mi => memberInfo.Name == mi.Name); 
    } 
} 

उपयोग करने के लिए यह सिर्फ अपने JsonSerializer की ContractResolver संपत्ति में एक उदाहरण डाल दिया। जिश्ती द्वारा दी गई परिपत्र निर्भरता समस्या को संदर्भ लूपहैंडलिंग प्रॉपर्टी को संदर्भ लूपहैंडलिंग में सेट करके हल किया जा सकता है। अनदेखा करें। यहाँ एक विस्तार विधि है कि Json.Net

public static void SerializeToJsonFile<T>(this T itemToSerialize, string filePath) 
    { 
    using (StreamWriter streamWriter = new StreamWriter(filePath)) 
    { 
     using (JsonWriter jsonWriter = new JsonTextWriter(streamWriter)) 
     { 
     jsonWriter.Formatting = Formatting.Indented; 
     JsonSerializer serializer = new JsonSerializer 
      { 
      NullValueHandling = NullValueHandling.Ignore, 
      ReferenceLoopHandling = ReferenceLoopHandling.Ignore, 
      ContractResolver = new NHibernateContractResolver(), 
      }; 
     serializer.Serialize(jsonWriter, itemToSerialize); 
     } 
    } 
    } 
+2

इस कोड के लिए धन्यवाद, यह बहुत अच्छा काम करता है! और मुझे एक स्टेटलेस सत्र का उपयोग करने से बचाया। –

+0

यह JSON.NET 3.5 रिलीज 7 में काम करना बंद कर दिया है, लेकिन अभी भी 3.5 रिलीज 5 में ठीक काम करता है। – zcrar70

+0

उन्होंने रिलीज 6 के रूप में असेंबली वर्जन को अपडेट किया है, जिसका अर्थ है कि यदि आपने पहले इस फ़ाइल को अपने समाधान में शामिल किया था, तो संस्करण मेल नहीं खाएगा , और कुछ प्रकार की सुरक्षा अपवाद फेंक दें। क्या यह मामला हो सकता है? – jishi

23

का उपयोग कर हम इस सटीक समस्या है, जो यहाँ Handcraftsman की प्रतिक्रिया से प्रेरणा के साथ हल किया गया था वस्तुओं को क्रमानुसार करने इस्तेमाल किया जा सकता है।

समस्या JSON.NET से उत्पन्न होती है कैसे NHibernate के प्रॉक्सी वर्गों को क्रमानुसार करने के बारे में भ्रमित किया जा रहा। समाधान: प्रॉक्सी उदाहरणों को उनके बेस क्लास की तरह क्रमबद्ध करें।

Handcraftsman के कोड का एक सरलीकृत संस्करण इस प्रकार है:

public class NHibernateContractResolver : DefaultContractResolver { 
    protected override List<MemberInfo> GetSerializableMembers(Type objectType) { 
     if (typeof(INHibernateProxy).IsAssignableFrom(objectType)) { 
      return base.GetSerializableMembers(objectType.BaseType); 
     } else { 
      return base.GetSerializableMembers(objectType); 
     } 
    } 
} 

IMHO, इस कोड को अभी भी JSON.NET के डिफ़ॉल्ट कस्टम विशेषताओं, आदि के बारे में व्यवहार पर निर्भर का लाभ दिया है (और कोड एक बहुत है कम!)।

ऐसा लगता है कि इस

 var serializer = new JsonSerializer{ 
      ReferenceLoopHandling = ReferenceLoopHandling.Ignore, 
      ContractResolver = new NHibernateContractResolver() 
     }; 
     StringWriter stringWriter = new StringWriter(); 
     JsonWriter jsonWriter = new Newtonsoft.Json.JsonTextWriter(stringWriter);     
     serializer.Serialize(jsonWriter, objectToSerialize); 
     string serializedObject = stringWriter.ToString(); 

नोट प्रयोग किया जाता है: इस कोड के लिए लिखा और NHibernate 2.1 के साथ इस्तेमाल किया गया था। जैसा कि कुछ टिप्पणीकारों ने बताया है, यह एनएचबीर्नेट के बाद के संस्करणों के साथ बॉक्स से बाहर काम नहीं करता है, आपको कुछ समायोजन करना होगा। अगर मुझे कभी भी NHibernate के बाद के संस्करणों के साथ ऐसा करना है तो मैं कोड को अपडेट करने का प्रयास करूंगा।

+0

मेरे लिए बहुत अच्छा काम किया! –

+0

मैं उलझन में हूं कि इस कोड का उपयोग कब किया जाएगा और कैसे। – Ciel

+0

लाइडमैन का समाधान अब और काम नहीं करता है क्योंकि इंटरफ़ेस इतना ऑब्जेक्ट टाइप है। बेसटाइप शून्य और क्रैश देता है –

41

मैं एक ही समस्या का सामना करना पड़ रहा था तो मैं उपयोग करने के लिए @ Liedman के कोड की कोशिश की लेकिन GetSerializableMembers() प्रॉक्सी संदर्भ के लिए कभी नहीं कहा जाता हो गया था। मैंने पाया ओवरराइड करने के लिए एक और तरीका:

public class NHibernateContractResolver : DefaultContractResolver 
    { 
     protected override JsonContract CreateContract(Type objectType) 
     { 
      if (typeof(NHibernate.Proxy.INHibernateProxy).IsAssignableFrom(objectType)) 
       return base.CreateContract(objectType.BaseType); 
      else 
       return base.CreateContract(objectType); 
     } 
    } 
+3

+1 - यह एनएच 3.3 और JSON.NET 4.5.7 के साथ अभी एकमात्र कामकाजी संस्करण प्रतीत होता है। – TheCloudlessSky

+0

और शायद आप इसे इस तरह उपयोग करना चाहते हैं: JsonConvert।DefaultSettings =() => नई JsonSerializerSettings \t \t \t { \t \t \t \t ContractResolver = नए NHibernateContractResolver() \t \t \t}; – PandaWood

+0

वास्तव में, मैं यह करने की कोशिश की और यह JSON नेट 5.06 और राष्ट्रीय राजमार्ग 3.3 – PandaWood

1

मैं कहता हूँ कि हम इस मेरी राय में एक डिजाइन समस्या है। चूंकि एनएच सभी के नीचे डेटाबेस से कनेक्शन बनाता है और मध्य में प्रॉक्सी है, तो आपके आवेदन की पारदर्शिता के लिए उन्हें सीधे क्रमबद्ध करने के लिए अच्छा नहीं है (और जैसा कि आप देख सकते हैं कि जेसन.नेट उन्हें बिल्कुल पसंद नहीं करता है)।

आपको इकाइयों को क्रमबद्ध नहीं करना चाहिए, लेकिन आपको उन्हें "दृश्य" ऑब्जेक्ट्स या पीओसीओ या डीटीओ ऑब्जेक्ट्स (जिसे आप उन्हें कॉल करना चाहते हैं) में परिवर्तित करना चाहिए और फिर इन्हें क्रमबद्ध करना चाहिए।

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

एफके का प्रबंधन कैसे करें? मेरा व्यक्तिगत नियम है:

इकाई का स्तर: व्यक्ति वर्ग और

देखें स्तर जुड़े एक लिंग वर्ग के साथ: GenderId और GenderName गुणों के साथ व्यक्ति दृश्य।

इसका मतलब है कि वस्तुओं को देखने के दौरान आपको अपनी गुणों को प्राइमेटिव में विस्तारित करने की आवश्यकता है। इस तरह आपकी जेसन ऑब्जेक्ट्स को संभालने में आसान और आसान भी है।

जब आपको डीबी में परिवर्तनों को धक्का देने की आवश्यकता होती है, तो मेरे मामले में मैं ऑटोमैपर का उपयोग करता हूं और वैल्यू रिसेल्वर क्लास करता हूं जो आपके नए ग्रिड को लिंग ऑब्जेक्ट में परिवर्तित कर सकता है।

अद्यतन: एनएच से सीधे (एलियास टोबियन) देखने के लिए http://blog.andrewawhitaker.com/blog/2014/06/19/queryover-series-part-4-transforming/ देखें। यह डीबी पक्ष में एक बढ़ावा होगा।