'SubSonic.Schema .DatabaseColumn' प्रकार के ऑब्जेक्ट को क्रमांकित करते समय एक परिपत्र संदर्भ का पता लगाया गया था।


170

मैं एक साधारण JSON रिटर्न करने की कोशिश कर रहा हूं, लेकिन मेरे पास नीचे दिए गए मुद्दे हैं।

public JsonResult GetEventData()
{
    var data = Event.Find(x => x.ID != 0);
    return Json(data);
}

मुझे इस प्रश्न के शीर्षक में दिखाए गए अपवाद के साथ एक HTTP 500 मिलता है। मैंने भी कोशिश की

var data = Event.All().ToList()

उसी ने समस्या दी।

क्या यह बग या मेरा कार्यान्वयन है?


1
इस को देखो। ScriptIgnoreविशेषता का उपयोग करके एक समाधान है । stackoverflow.com/questions/1193857/subsonic-3-0-2-2-structs-tt
freddoo

यह मेरे लिए सबसे अच्छा समाधान था; मेरे पास गेम> टूर्नामेंट> गेम> टूर्नामेंट> गेम, आदि था। मैंने ScriptIgnoreटूर्नामेंट के लिए एक विशेषता रखी। संपत्ति और यह ठीक काम किया :)
eth0

: मामले में किसी को "स्वचालित" चाहता है (नहीं सबसे अच्छा अभ्यास) है कि बिना किसी अतिरिक्त कोड की आवश्यकता है, इस गुणवत्ता आश्वासन की जाँच इस समस्या के लिए समाधान JSON (ServiceStack.Text पुस्तकालय) में इकाई की रूपरेखा श्रेणी संदर्भ को क्रमानुसार क्या नहीं
nikib3ro

जवाबों:


175

ऐसा लगता है कि आपकी वस्तु पदानुक्रम में परिपत्र संदर्भ हैं जो JSON धारावाहिक द्वारा समर्थित नहीं है। क्या आपको सभी स्तंभों की आवश्यकता है? आप केवल वे गुण देख सकते हैं जिनकी आपको आवश्यकता है:

return Json(new 
{  
    PropertyINeed1 = data.PropertyINeed1,
    PropertyINeed2 = data.PropertyINeed2
});

यह आपके JSON ऑब्जेक्ट को हल्का और समझने में आसान बना देगा। यदि आपके पास कई गुण हैं, तो AutoMapper का उपयोग डीटीओ ऑब्जेक्ट और व्यू ऑब्जेक्ट के बीच स्वचालित रूप से मैप करने के लिए किया जा सकता है ।


मुझे लगता है कि शायद जो मैं चाहता हूं वह काम कर सकता है मुझे लगता है कि मुझे लगता है कि परिपत्र संदर्भ इसलिए है क्योंकि इवेंट में मेरे पास IQueryable <श्रेणी> है जो बदले में एक IQueryable <इवेंट> होगा
जॉन

7
Automapper कोई गारंटी नहीं है कि आपको यह समस्या नहीं होगी। मैं यहां एक उत्तर की तलाश में आया था और मैं वास्तव में ऑटोमैपर का उपयोग कर रहा हूं।
कैप्टन केनपाची

1
उत्तर देखें @ClayKaboom से क्योंकि यह बताता है कि यह परिपत्र क्यों हो सकता है
पांडावुड

106

मैं एक ही समस्या थी और द्वारा हल using Newtonsoft.Json;

var list = JsonConvert.SerializeObject(model,
    Formatting.None,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});

return Content(list, "application/json");

3
इस इनलाइन कोड ने मेरे लिए ठीक काम किया। Kravits88 द्वारा उल्लिखित वैश्विक विन्यास में वही सामान मेरे लिए काम नहीं कर रहा है। ALSO, इस कोड के लिए ContentResult को वापस करने के लिए विधि हस्ताक्षर को अपडेट किया जाना चाहिए।
BiLaL

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

56

यह वास्तव में होता है क्योंकि जटिल वस्तुएं होती हैं जो परिणामी जोंस वस्तु को विफल कर देती हैं। और यह विफल हो जाता है क्योंकि जब ऑब्जेक्ट मैप किया जाता है तो यह बच्चों को मैप करता है, जो अपने माता-पिता को मैप करता है, जो कि एक परिपत्र संदर्भ होता है। Json इसे प्रसारित करने में अनंत समय लगाएगा, इसलिए यह समस्या को अपवाद के साथ रोकता है।

एंटिटी फ्रेमवर्क मैपिंग भी समान व्यवहार पैदा करता है, और समाधान सभी अवांछित गुणों को त्यागना है।

बस अंतिम उत्तर की खोज में, पूरा कोड होगा:

public JsonResult getJson()
{
    DataContext db = new DataContext ();

    return this.Json(
           new {
                Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
               }
           , JsonRequestBehavior.AllowGet
           );
}

यदि आप किसी Resultसंपत्ति के अंदर वस्तुएं नहीं चाहते हैं तो यह निम्नलिखित हो सकता है :

public JsonResult getJson()
{
    DataContext db = new DataContext ();

    return this.Json(
           (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
           , JsonRequestBehavior.AllowGet
           );
}

1
+1 स्पष्ट और आसान चीज़ों को समझने के लिए, धन्यवाद @Clay। मुझे त्रुटि के पीछे की अवधारणाओं के बारे में आपका स्पष्टीकरण पसंद है।
Ajay2707

14

चीजों को योग करने के लिए, इसके 4 समाधान हैं:

समाधान 1: DBContext के लिए ProxyCreation को बंद करें और अंत में इसे पुनर्स्थापित करें।

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        bool proxyCreation = db.Configuration.ProxyCreationEnabled;
        try
        {
            //set ProxyCreation to false
            db.Configuration.ProxyCreationEnabled = false;

            var data = db.Products.ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
        finally
        {
            //restore ProxyCreation to its original state
            db.Configuration.ProxyCreationEnabled = proxyCreation;
        }
    }

समाधान 2: सीरियल सेटिंग्स पर ध्यान न देने के लिए ReferenceLoopHandling की स्थापना करके JsonConvert का उपयोग करना।

    //using using Newtonsoft.Json;

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.ToList();

            JsonSerializerSettings jss = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
            var result = JsonConvert.SerializeObject(data, Formatting.Indented, jss);

            return Json(result, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }

निम्नलिखित दो समाधान समान हैं, लेकिन एक मॉडल का उपयोग करना बेहतर है क्योंकि यह मजबूत टाइप किया गया है।

समाधान 3: एक मॉडल लौटाएं जिसमें केवल आवश्यक गुण शामिल हैं।

    private DBEntities db = new DBEntities();//dbcontext

    public class ProductModel
    {
        public int Product_ID { get; set;}

        public string Product_Name { get; set;}

        public double Product_Price { get; set;}
    }

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.Select(p => new ProductModel
                                                {
                                                    Product_ID = p.Product_ID,
                                                    Product_Name = p.Product_Name,
                                                    Product_Price = p.Product_Price
                                                }).ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }

समाधान 4: एक नया गतिशील ऑब्जेक्ट लौटाएं जिसमें केवल आवश्यक गुण शामिल हैं।

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.Select(p => new
                                                {
                                                    Product_ID = p.Product_ID,
                                                    Product_Name = p.Product_Name,
                                                    Product_Price = p.Product_Price
                                                }).ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }

7

JSON, xml और विभिन्न अन्य स्वरूपों की तरह, एक ट्री-आधारित क्रमांकन प्रारूप है। यदि आप अपनी वस्तुओं में परिपत्र संदर्भ रखते हैं तो यह आपको पसंद नहीं आएगा, क्योंकि "पेड़" होगा:

root B => child A => parent B => child A => parent B => ...

अक्सर एक निश्चित पथ के साथ नेविगेशन को अक्षम करने के तरीके होते हैं; उदाहरण के लिए, XmlSerializerआप मूल संपत्ति को चिह्नित कर सकते हैं XmlIgnore। मुझे नहीं पता कि यह प्रश्न में जसन धारावाहिक के साथ संभव है या नहीं, और क्या DatabaseColumnइसके उपयुक्त मार्कर हैं ( बहुत ही संभावना नहीं है, क्योंकि इसे हर क्रमबद्ध एपीआई को संदर्भित करना होगा)


4

इसकी वजह DbContext T4 टेम्पलेट है जो कि EntityFramework संस्थाएं बनाने के लिए उपयोग किया जाता है। परिवर्तन ट्रैकिंग करने में सक्षम होने के लिए, यह टेम्प्लेट अपने अच्छे POCO को उनके साथ लपेटकर प्रॉक्सी पैटर्न का उपयोग करता है। यह तब समस्याओं का कारण बनता है जब JavaScriptSerializer के साथ क्रमबद्ध किया जाता है।

तो फिर 2 समाधान हैं:

  1. या तो आप केवल सीरियल करें और क्लाइंट पर आपकी ज़रूरत के गुणों को लौटाएँ
  2. आप संदर्भ के कॉन्फ़िगरेशन पर इसे सेट करके प्रॉक्सी की स्वचालित पीढ़ी को बंद कर सकते हैं

    संदर्भ।

नीचे के लेख में बहुत अच्छी तरह से समझाया गया है।

http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/


4

Newtonsoft.Json का उपयोग करना: अपने Global.asax Application_Start पद्धति में इस पंक्ति को जोड़ें:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

1
स्पष्ट रूप से बहुत आगे दिखता है, लेकिन मेरे लिए काम नहीं किया
BiLaL

4

[JsonIgnore]अपने मॉडल में वर्चुअल गुण जोड़ें ।


4

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


3

बशर्ते उत्तर अच्छे हों, लेकिन मुझे लगता है कि "वास्तुशिल्प" के परिप्रेक्ष्य को जोड़कर उनमें सुधार किया जा सकता है।

जाँच पड़ताल

MVC's Controller.Jsonफ़ंक्शन काम कर रहा है, लेकिन यह इस मामले में एक प्रासंगिक त्रुटि प्रदान करने में बहुत खराब है। का उपयोग करके Newtonsoft.Json.JsonConvert.SerializeObject, त्रुटि निर्दिष्ट करती है कि वह संपत्ति क्या है जो परिपत्र संदर्भ को ट्रिगर कर रही है। अधिक जटिल वस्तु पदानुक्रम को क्रमबद्ध करते समय यह विशेष रूप से उपयोगी है।

उचित वास्तुकला

किसी को डेटा मॉडल (उदाहरण के लिए ईएफ मॉडल) को क्रमबद्ध करने की कोशिश नहीं करनी चाहिए, क्योंकि ओआरएम के नेविगेशन गुण क्रमबद्धता की बात करते हैं। डेटा प्रवाह निम्न होना चाहिए:

Database -> data models -> service models -> JSON string 

सेवा मॉडल ऑटो मैपर्स (जैसे ऑटोमैपर ) का उपयोग करके डेटा मॉडल से प्राप्त किया जा सकता है । हालांकि यह परिपत्र संदर्भों की कमी की गारंटी नहीं देता है, उचित डिजाइन को यह करना चाहिए: सेवा मॉडल में वही होना चाहिए जो सेवा उपभोक्ता की आवश्यकता होती है (यानी गुण)।

उन दुर्लभ मामलों में, जब ग्राहक विभिन्न स्तरों पर एक ही वस्तु प्रकार को शामिल करते हुए पदानुक्रम का अनुरोध करता है, तो सेवा माता-पिता के साथ एक रेखीय संरचना बना सकती है-> बाल संबंध (केवल पहचानकर्ताओं का उपयोग कर, संदर्भ नहीं)।

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

  1. किसी ईवेंट को एक्सेस करना - केवल हेडर डेटा (पहचानकर्ता, नाम, तिथि आदि) लोड किया जाता है -> सर्विस मॉडल (JSON) जिसमें केवल हेडर डेटा होता है
  2. प्रबंधित सहभागियों की सूची - एक पॉपअप का उपयोग करें और आलसी सूची को लोड करें -> सेवा मॉडल (JSON) जिसमें केवल उपस्थित लोगों की सूची है

1

मैं फिक्स का उपयोग कर रहा हूं, क्योंकि MVC5 विचारों में नॉकआउट का उपयोग कर रहा हूं।

कार्रवाई पर

return Json(ModelHelper.GetJsonModel<Core_User>(viewModel));

समारोह

   public static TEntity GetJsonModel<TEntity>(TEntity Entity) where TEntity : class
    {
        TEntity Entity_ = Activator.CreateInstance(typeof(TEntity)) as TEntity;
        foreach (var item in Entity.GetType().GetProperties())
        {
            if (item.PropertyType.ToString().IndexOf("Generic.ICollection") == -1 && item.PropertyType.ToString().IndexOf("SaymenCore.DAL.") == -1)
                item.SetValue(Entity_, Entity.GetPropValue(item.Name));
        }
        return Entity_;  
    }

0

आप उन गुणों को नोटिस कर सकते हैं जो परिपत्र संदर्भ का कारण बनते हैं। तब आप कुछ ऐसा कर सकते हैं:

private Object DeCircular(Object object)
{
   // Set properties that cause the circular reference to null

   return object
}

-1
//first: Create a class as your view model

public class EventViewModel 
{
 public int Id{get;set}
 public string Property1{get;set;}
 public string Property2{get;set;}
}
//then from your method
[HttpGet]
public async Task<ActionResult> GetEvent()
{
 var events = await db.Event.Find(x => x.ID != 0);
 List<EventViewModel> model = events.Select(event => new EventViewModel(){
 Id = event.Id,
 Property1 = event.Property1,
 Property1 = event.Property2
}).ToList();
 return Json(new{ data = model }, JsonRequestBehavior.AllowGet);
}

यह इस सवाल का जवाब नहीं देता है
डेन आई

-1

इस समस्या को हल करने के लिए एक आसान विकल्प एक स्ट्रिंग लौटना है, और उस स्ट्रिंग को JavaScriptSerializer के साथ json करने के लिए प्रारूपित करना है।

public string GetEntityInJson()
{
   JavaScriptSerializer j = new JavaScriptSerializer();
   var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
   return j.Serialize(entityList );
}

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

यह मत करो:

public string GetEntityInJson()
{
   JavaScriptSerializer j = new JavaScriptSerializer();
   var entityList = dataContext.Entitites.toList();
   return j.Serialize(entityList );
}

इसके बजाय ऐसा करें यदि आप पूरी तालिका नहीं चाहते हैं:

public string GetEntityInJson()
{
   JavaScriptSerializer j = new JavaScriptSerializer();
   var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
   return j.Serialize(entityList );
}

यह कम डेटा के साथ एक दृश्य प्रस्तुत करने में मदद करता है, बस आपके द्वारा आवश्यक विशेषताओं के साथ, और आपके वेब को तेज़ी से चलाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.