2010-01-04 15 views
37

मेरे पास एक वस्तु है जिसमें किसी अन्य वस्तु का परिपत्र संदर्भ है। इन वस्तुओं के बीच संबंधों को देखते हुए यह सही डिजाइन है।जेसन और परिपत्र संदर्भ अपवाद

Machine => Customer => Machine 

के रूप में की उम्मीद है जब मैं Json उपयोग करने के लिए एक मशीन या ग्राहक वस्तु क्रमानुसार करने की कोशिश मैं एक मुद्दा में चलाने वर्णन करने के लिए। मुझे इस बात का अनिश्चितता है कि इस मुद्दे को कैसे हल किया जाए क्योंकि मैं मशीन और ग्राहक वस्तुओं के बीच संबंध तोड़ना नहीं चाहता हूं। इस मुद्दे को हल करने के विकल्प क्या हैं?

संपादित

वर्तमान में मैं Json method provided by the Controller base class उपयोग कर रहा हूँ।

Json(machineForm); 

उत्तर

51

अद्यतन: के रूप में JavaScriptSerializer जाहिरा तौर पर यह ध्यान नहीं देता

, NonSerializedAttribute उपयोग करने का प्रयास न करें।

इसके बजाय, System.Web.Script.Serialization में ScriptIgnoreAttribute का उपयोग करें।

public class Machine 
{ 
    public string Customer { get; set; } 

    // Other members 
    // ... 
} 

public class Customer 
{ 
    [ScriptIgnore] 
    public Machine Machine { get; set; } // Parent reference? 

    // Other members 
    // ... 
} 

इस तरह, जब आप Json विधि में एक Machine टॉस, यह Customer को Machine से संबंध पार करेगा, लेकिन Customer से Machine करने के लिए वापस जाने की कोशिश नहीं करेंगे।

रिश्ते अभी भी आपके कोड के लिए ऐसा करने के लिए है, लेकिन JavaScriptSerializer (Json विधि द्वारा उपयोग किया जाता है) इसे अनदेखा कर देगा।

+0

मुझे इसे एक शॉट देना होगा, लेकिन दुर्भाग्यवश यह डोमेन/कोर ऑब्जेक्ट से आ रहा है और मुझे यकीन नहीं है कि मैं System.Web.Script का संदर्भ प्रस्तुत करना चाहता हूं। उस प्रोजेक्ट में सरलीकरण। मैं इन मूल वस्तुओं को एक मॉडल में encapsulating हूँ जो मुझे लगता है कि मैं 'ScriptIgnore' का उपयोग कर सकता हूं, लेकिन उस समय मैं परिपत्र संदर्भ को हटा सकता था। यह समाधान अज्ञात प्रकारों के साथ एक समान समाधान प्रदान करता प्रतीत होता है http://stackoverflow.com/questions/372955/best-way-to-filter-domain-objects-for-json-output-in-an-asp-net -एमवीसी-एप्लिकेशन/372977 # 372977 – ahsteele

+0

यह भी काम करता है। आपको अपने प्रश्न/टिप्पणियों के साथ विशिष्ट होना चाहिए - यह कहकर कि आप परिपत्र संदर्भ को हटा नहीं सकते/नहीं करेंगे यह कहने से अलग है कि आप मॉडल में कुछ भी नहीं बदल सकते/नहीं। मैं अक्सर अज्ञात प्रकारों में 'जेसन' में जाता हूं, केवल एकमात्र मुद्दा जो मैं यहां देखता हूं वह यह है कि यदि आपके पास JSON'ed 'मशीन' लौटने वाली एक से अधिक विधि हैं, तो आपको हर बार इसे" फ़िल्टर "करना याद रखना होगा। यह मेरी आंखों में चॉकलेट बनाम वेनिला है - वे दोनों अच्छे विकल्प हैं। – Aaronaught

+0

@ एरोन समझा। यह सुनिश्चित नहीं है कि मैं यह सुनिश्चित नहीं कर सकता कि यह किसी विशेष यूआई स्थिति के लिए इस समाधान को प्रदान करने के लिए कोर/डोमेन प्रोजेक्ट के संदर्भ को जोड़ने का अधिकार * महसूस करता है। मुझे सिस्टम नेमस्पेस में NonSerializedAttribute का उपयोग करके समाधान पसंद आया। ऐसा लगता है कि जावास्क्रिप्टसेरियलाइज़र इसे अनदेखा करता है। – ahsteele

1

, के बाद से मेरी जानकारी के लिए, आप वस्तु के संदर्भ को क्रमानुसार नहीं कर सकता है, लेकिन केवल प्रतियां आपको लगता है कि कुछ इस तरह चला जाता है एक गंदा हैक का एक सा रोजगार की कोशिश कर सकते:: तो क्रमबद्धता मैं कर रहा हूँ के रूप में के रूप में बुनियादी है

  1. ग्राहक मशीन की आईडी
  2. के रूप में अपनी मशीन संदर्भ को क्रमानुसार जब आप json कोड आप तो है कि उचित संदर्भ में उन आईडी के बदल देती है यह की चोटी पर एक साधारण समारोह चला सकते हैं deserialize चाहिए।
+0

निश्चित है लेकिन यह मशीनिंग जानकारी को क्वेरी पेज पर नहीं पहुंचाता है और मशीन गुणों को प्राप्त करने के लिए अतिरिक्त प्रश्नों की आवश्यकता होगी। – ahsteele

0

आपको यह तय करने की आवश्यकता है कि "रूट" ऑब्जेक्ट कौन सा है। कहें मशीन जड़ है, तो ग्राहक मशीन का उप-ऑब्जेक्ट है। जब आप सीरियलाइज मशीन करते हैं, तो यह ग्राहक को JSON में उप-ऑब्जेक्ट के रूप में क्रमबद्ध करेगा, और जब ग्राहक को क्रमबद्ध किया जाता है, तो यह नहीं धारावाहिक मशीन के पीछे संदर्भ है। जब आपका कोड मशीन को deserialises, यह मशीन के ग्राहक उप-वस्तु deserialise और ग्राहक से मशीन के पीछे संदर्भ बहाल करेगा।

अधिकांश धारावाहिक पुस्तकालय प्रत्येक वर्ग के लिए deserialisation कैसे किया जाता है यह संशोधित करने के लिए कुछ प्रकार के हुक प्रदान करते हैं। मशीन के ग्राहक के लिए मशीन के ग्राहक में बैकरेफर को बहाल करने के लिए आपको deserialisation को संशोधित करने के लिए उस हुक का उपयोग करना होगा। वास्तव में वह हुक जो JSON लाइब्रेरी का उपयोग कर रहा है उस पर निर्भर करता है।

4

एक ही समस्या के लिए उपयोग करें। मैंने एक साधारण विस्तार विधि बनाई है, जो एक आईडीआईआरआई में एल 2 ई ऑब्जेक्ट्स को "flattens" करता है।एक IDictionary जावास्क्रिप्टसेरियलज़र द्वारा सही ढंग से क्रमबद्ध किया जाता है। परिणामी जेसन वस्तु को सीधे क्रमबद्ध करने जैसा ही है।

चूंकि मैं क्रमबद्धता के स्तर को सीमित करता हूं, परिपत्र संदर्भ से बचा जाता है। इसमें 1-> एन लिंक्ड टेबल (एंटिटीसेट्स) शामिल नहीं होंगे।

private static IDictionary<string, object> JsonFlatten(object data, int maxLevel, int currLevel) { 
     var result = new Dictionary<string, object>(); 
     var myType = data.GetType(); 
     var myAssembly = myType.Assembly; 
     var props = myType.GetProperties(); 
     foreach (var prop in props) { 
      // Remove EntityKey etc. 
      if (prop.Name.StartsWith("Entity")) { 
       continue; 
      } 
      if (prop.Name.EndsWith("Reference")) { 
       continue; 
      } 
      // Do not include lookups to linked tables 
      Type typeOfProp = prop.PropertyType; 
      if (typeOfProp.Name.StartsWith("EntityCollection")) { 
       continue; 
      } 
      // If the type is from my assembly == custom type 
      // include it, but flattened 
      if (typeOfProp.Assembly == myAssembly) { 
       if (currLevel < maxLevel) { 
        result.Add(prop.Name, JsonFlatten(prop.GetValue(data, null), maxLevel, currLevel + 1)); 
       } 
      } else { 
       result.Add(prop.Name, prop.GetValue(data, null)); 
      } 
     } 

     return result; 
    } 
    public static IDictionary<string, object> JsonFlatten(this Controller controller, object data, int maxLevel = 2) { 
     return JsonFlatten(data, maxLevel, 1); 
    } 

मेरे कार्रवाई विधि इस प्रकार है:

public JsonResult AsJson(int id) { 
     var data = Find(id); 
     var result = this.JsonFlatten(data); 
     return Json(result, JsonRequestBehavior.AllowGet); 
    } 
31

मैं अपनी उम्र के बावजूद इस का जवाब दे रहा हूँ क्योंकि यह गूगल से "json.encode वृत्तीय संदर्भ" के लिए और यद्यपि 3 परिणाम (वर्तमान में) है मैं ऊपर दिए गए उत्तरों (पूरी तरह से) से सहमत नहीं हूं, उसमें ScriptIgnoreAttribute का उपयोग करके मान लिया जाता है कि आप अपने कोड में कहीं भी कुछ JSON के लिए दूसरे दिशा में रिश्ते को पार करना नहीं चाहते हैं। मैं एक प्रयोग के मामले के कारण अपने मॉडल को लॉक करने में विश्वास नहीं करता हूं।

इससे मुझे इस सरल समाधान का उपयोग करने के लिए प्रेरित किया गया।

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

var jsonMachines = from m in machineForm 
        select new { m.X, m.Y, // other Machine properties you desire 
           Customer = new { m.Customer.Id, m.Customer.Name, // other Customer properties you desire 
           }}; 
return Json(jsonMachines); 

या अगर मशीन -> ग्राहक संबंध 1 है .. * -> * तो कोशिश:

var jsonMachines = from m in machineForm 
        select new { m.X, m.Y, // other machine properties you desire 
           Customers = new List<Customer>(
               (from c in m.Customers 
               select new Customer() 
               { 
                Id = c.Id, 
                Name = c.Name, 
                // Other Customer properties you desire 
               }).Cast<Customer>()) 
           }; 
return Json(jsonMachines); 
2

में Entity Framework version 4, एक विकल्प उपलब्ध है: ObjectContextOp tions.LazyLoadingEnabled

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

देखें: http://msdn.microsoft.com/en-us/library/bb896272.aspx

+0

आप कुछ मामलों में भी प्रॉक्सी जनरेशन को अक्षम करना पड़ सकता है। –

+0

नीचे एक उदाहरण जोड़ा गया: http://stackoverflow.com/a/17068227/605586 – Thomas

9

TXL के जवाब के आधार पर आप अक्षम आलसी लोड हो रहा है और प्रॉक्सी निर्माण के लिए है और आप सामान्य तरीकों का उपयोग अपने डेटा प्राप्त करने के लिए कर सकते हैं।

उदाहरण:

//Retrieve Items with Json: 
public JsonResult Search(string id = "") 
{ 
    db.Configuration.LazyLoadingEnabled = false; 
    db.Configuration.ProxyCreationEnabled = false; 

    var res = db.Table.Where(a => a.Name.Contains(id)).Take(8); 

    return Json(res, JsonRequestBehavior.AllowGet); 
} 
+0

धन्यवाद - यह इस प्रश्न में मेरा पसंदीदा समाधान है क्योंकि यह एक सबसेट में "बैक आउट" के लिए अधिक कोड का उपयोग करने के बजाय अनावश्यक रूपरेखा गणना को रोकता है अनावश्यक काम निष्पादित करने के बाद डेटा। – Stephen

+0

एचएफएस ने मुझे यह खोजने में 3 दिन लगे, लेकिन इस समाधान को पोस्ट करने के लिए आपको बहुत धन्यवाद !!!! – user3320597

0

मैं इस सप्ताह के रूप में अच्छी तरह से एक ही समस्या मिला है, और अनाम प्रकार का उपयोग नहीं कर सकता है क्योंकि मैं एक अंतरफलक एक List<MyType> के लिए पूछ लागू करने की जरूरत। नेविगेटिबिलिटी के साथ सभी रिश्तों को दिखाते हुए चित्र बनाने के बाद, मुझे पता चला कि MyTypeMyObject के साथ एक द्विपक्षीय संबंध था जिसके कारण यह परिपत्र संदर्भ हुआ, क्योंकि वे दोनों एक-दूसरे को बचाते थे।

यह तय करने के बाद कि MyObject को MyType को वास्तव में जानने की आवश्यकता नहीं थी, और इस प्रकार इसे एक unidirectional संबंध बनाने की समस्या हल हो गई थी।

0

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

SessionTickets result = GetTicketsSession(); 
foreach(var r in result.Tickets) 
{ 
    r.TicketTypes = null; //those two were creating the problem 
    r.SelectedTicketType = null; 
} 
return Json(result); 

तुम सच में अपने गुण की जरूरत है, तो आप एक viewmodel जो वृत्तीय संदर्भ नहीं रखता है बना सकते हैं, लेकिन शायद, महत्वपूर्ण तत्व के कुछ पहचान रखता है कि आप मूल मूल्य बहाल करने के लिए बाद में इस्तेमाल कर सकते हैं।

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