JSON.NET त्रुटि प्रकार के लिए पाया गया स्वयं संदर्भित संदर्भित लूप त्रुटि


494

मैंने POCO वर्ग को क्रमबद्ध करने की कोशिश की जो स्वतः ही Entity Data Model .edmx से उत्पन्न हुआ और जब मैंने उपयोग किया

JsonConvert.SerializeObject 

मुझे निम्नलिखित त्रुटि मिली:

प्रकार: System.data.entity के लिए त्रुटि स्वयं संदर्भित लूप का पता चलता है।

मैं इस समस्या का समाधान कैसे कर सकता हूं।



जब आप Linq और MVC का उपयोग कर रहे हैं: stackoverflow.com/a/38241856
aDDin

.NET कोर 2 का उपयोग करते समय: stackoverflow.com/a/48709134/4496145
डेव स्कैंडर

2
यह त्रुटि मेरे साथ हुई, जब मैं एक asyncविधि कॉल (ए Task) के परिणाम को क्रमबद्ध करना चाहता था और awaitबयान को उपसर्ग करना भूल गया ।
उवे कीम

जवाबों:


485

यही सबसे अच्छा उपाय था https://code.msdn.microsoft.com/Loop-Reference-handling-in-cafaf7

फिक्स 1: विश्व स्तर पर परिपत्र संदर्भ को अनदेखा करना

(मैंने इसे चुना है / कोशिश की है, जैसा कि कई अन्य लोगों ने किया है)

Json.net serializer के पास परिपत्र संदर्भों को अनदेखा करने का एक विकल्प है। WebApiConfig.csफ़ाइल में निम्न कोड डालें :

 config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling 
= Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

सरल फिक्स धारावाहिक को संदर्भ को अनदेखा कर देगा जो एक लूप का कारण होगा। हालाँकि, इसकी सीमाएँ हैं:

  • डेटा लूपिंग संदर्भ जानकारी खो देता है
  • फिक्स केवल JSON.net पर लागू होता है
  • यदि एक गहरी संदर्भ श्रृंखला है, तो संदर्भ के स्तर को नियंत्रित नहीं किया जा सकता है

यदि आप एक गैर- api ASP.NET प्रोजेक्ट में इस फ़िक्स का उपयोग करना चाहते हैं, तो आप उपरोक्त पंक्ति को जोड़ सकते हैं Global.asax.cs, लेकिन पहले जोड़ें:

var config = GlobalConfiguration.Configuration;

यदि आप .Net कोर प्रोजेक्ट में इसका उपयोग करना चाहते हैं , तो आप इस प्रकार बदल सकते हैं Startup.cs:

  var mvc = services.AddMvc(options =>
        {
           ...
        })
        .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

फिक्स 2: विश्व स्तर पर परिपत्र संदर्भ को संरक्षित करना

यह दूसरा फिक्स पहले जैसा है। बस कोड बदलें:

config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling 
     = Newtonsoft.Json.ReferenceLoopHandling.Serialize;     
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling 
     = Newtonsoft.Json.PreserveReferencesHandling.Objects;

इस सेटिंग को लागू करने के बाद डेटा का आकार बदल जाएगा।

[
   {
      "$id":"1",
      "Category":{
         "$id":"2",
         "Products":[
            {
               "$id":"3",
               "Category":{
                  "$ref":"2"
               },
               "Id":2,
               "Name":"Yogurt"
            },
            {
               "$ref":"1"
            }
         ],
         "Id":1,
         "Name":"Diary"
      },
      "Id":1,
      "Name":"Whole Milk"
   },
   {
      "$ref":"3"
   }
]

$ आईडी और $ रेफ सभी संदर्भों को रखता है और ऑब्जेक्ट ग्राफ स्तर को सपाट बनाता है, लेकिन क्लाइंट कोड को डेटा का उपभोग करने के लिए आकृति परिवर्तन को जानने की आवश्यकता है और यह केवल JSON.NET धारावाहिक के साथ भी लागू होता है।

फिक्स 3: संदर्भ विशेषताओं को अनदेखा और संरक्षित करें

यह फिक्स मॉडल या संपत्ति स्तर पर क्रमबद्ध व्यवहार को नियंत्रित करने के लिए मॉडल वर्ग पर विशेषताओं को सजाता है। संपत्ति की अनदेखी करने के लिए:

 public class Category 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 

        [JsonIgnore] 
        [IgnoreDataMember] 
        public virtual ICollection<Product> Products { get; set; } 
    } 

JSONIgnore JSON.NET के लिए है और XmlDCSerializer के लिए IgnoreDataMember है। संदर्भ को संरक्षित करने के लिए:

 // Fix 3 
        [JsonObject(IsReference = true)] 
        public class Category 
        { 
            public int Id { get; set; } 
            public string Name { get; set; } 

           // Fix 3 
           //[JsonIgnore] 
           //[IgnoreDataMember] 
           public virtual ICollection<Product> Products { get; set; } 
       } 

       [DataContract(IsReference = true)] 
       public class Product 
       { 
           [Key] 
           public int Id { get; set; } 

           [DataMember] 
           public string Name { get; set; } 

           [DataMember] 
           public virtual Category Category { get; set; } 
       }

JsonObject(IsReference = true)]JSON.NET के लिए है और [DataContract(IsReference = true)]XmlDCSerializer के लिए है। ध्यान दें: DataContractकक्षा में आवेदन करने के बाद , आपको DataMemberउन गुणों को जोड़ना होगा जिन्हें आप क्रमबद्ध करना चाहते हैं।

विशेषताओं को json और xml दोनों धारावाहिक पर लागू किया जा सकता है और मॉडल वर्ग पर अधिक नियंत्रण देता है।


7
फिक्स 3 मेरे लिए काम किया है। बस DataContract और DataMember विशेषताओं को हटा दें, और DTO पर JsonObject (IsReference = true) डालें। और यह काम करता है। धन्यवाद।
मेस्त्रो

1
यह एक GlobalConfiguration.Configuration
Bishoy Hanna

1
फिक्स 3 का यह फायदा है कि यह क्लाइंट कोड पर काम करता है, जहाँ GlobalConfiguration नहीं है
dumbledad

1
@ BishoyHanna, क्या आप इसे सामान्य ASP.NET अनुप्रयोगों से उपयोग करने की अनुमति देने के लिए अपना उत्तर संपादित कर सकते हैं? आप मेरे सुझाए गए संपादन का उपयोग कर सकते हैं: stackoverflow.com/review/suggested-edits/17797683
NH।

2
[JsonIgnore]मेरे ऊपर काम करने वाली विशेषता का उपयोग करना ।
नाथन बेक

467

JsonSerializerSettings का उपयोग करें

  • ReferenceLoopHandling.Error(डिफ़ॉल्ट) एक संदर्भ लूप का सामना करने पर त्रुटि करेगा। यही कारण है कि आपको एक अपवाद मिलता है।
  • ReferenceLoopHandling.Serialize उपयोगी है अगर ऑब्जेक्ट्स नेस्टेड हैं, लेकिन अनिश्चित काल तक नहीं।
  • ReferenceLoopHandling.Ignore किसी वस्तु को क्रमबद्ध नहीं करेगा यदि वह स्वयं की बाल वस्तु है।

उदाहरण:

JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented, 
new JsonSerializerSettings { 
        ReferenceLoopHandling = ReferenceLoopHandling.Serialize
});

क्या आपको किसी ऐसी वस्तु को अनुक्रमित करना चाहिए जो अनिश्चित काल के लिए निहित हो, आप StackOverflowException से बचने के लिए PreserveObjectReferences का उपयोग कर सकते हैं ।

उदाहरण:

JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented, 
new JsonSerializerSettings { 
        PreserveReferencesHandling = PreserveReferencesHandling.Objects
});

वह चुनें जो आपके द्वारा क्रमबद्ध वस्तु के लिए समझ में आता है।

संदर्भ http://james.newtonking.com/json/help/


66
मुझे एक धमाकेदार धारावाहिक बनाते समय त्रुटि का सामना करना पड़ा। मैंने ReferenceLoopHandling = ReferenceLoopHandling.Ignoreइसे काम करने के लिए इस्तेमाल किया

8
यदि डेटा में संदर्भ लूप हैं, ReferenceLoopHandling.Serializeतो धारावाहिक का उपयोग करते हुए अनंत पुनरावर्ती लूप में जाएगा और स्टैक को ओवरफ्लो करेगा।
ब्रायन रोजर्स

1
सही बात। जैसा कि एक ईएफ मॉडल के बारे में सवाल एक वैध चिंता का विषय है। सभी उपलब्ध विकल्प देने के लिए संशोधित।
DalSoft

1
मैंने एक ही त्रुटि का सामना किया है जब किसी वस्तु को क्रमबद्ध करने की कोशिश की जा रही है ... हालाँकि, वस्तु में किसी भी प्रकार के अलावा कोई संदर्भ नहीं है ..
Marin

1
मेरे लिए ईएफ इस समस्या का मुख्य कारण है क्योंकि स्व-संदर्भित संस्थाएं सभी जगह हैं।
तेमन शिपही

57

लूप संदर्भों को अनदेखा करना और उन्हें क्रमबद्ध नहीं करना है। में यह व्यवहार निर्दिष्ट है JsonSerializerSettings

JsonConvertएक अधिभार के साथ एकल :

JsonConvert.SerializeObject(YourObject, Formatting.Indented,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
    }
);

Application_Start()Global.asax.cs में कोड के साथ ग्लोबल सेटिंग :

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
     Formatting = Newtonsoft.Json.Formatting.Indented,
     ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};

संदर्भ: https://github.com/JamesNK/Newtonsoft.Json/issues/78


जब आप वैश्विक सेटिंग करते हैं तो आप इंडेंट करने का प्रारूप क्यों सेट करते हैं?
मर्फ़ब्रोब 2

बिल्कुल इस समस्या को हल करने के लिए हमें क्या चाहिए (एक तैनाती के दौरान पता चला)! आप दा आदमी .... हमें समय बचाने के लिए धन्यवाद !!
रयान ईस्टाब्रुक

मैंने "JsonConvert.DefaultSettings" = () => नए JsonSerializerSettings {....} को "Startup.cs"
Beldi Anouar

45

ऐसा करने का सबसे सरल तरीका है, Json.NET को nuget से इंस्टॉल करना और [JsonIgnore]क्लास में वर्चुअल प्रॉपर्टी में विशेषता जोड़ना , उदाहरण के लिए:

    public string Name { get; set; }
    public string Description { get; set; }
    public Nullable<int> Project_ID { get; set; }

    [JsonIgnore]
    public virtual Project Project { get; set; }

हालांकि इन दिनों, मैं केवल उन गुणों के साथ एक मॉडल बनाता हूं जिन्हें मैं चाहता हूं कि यह हल्का हो, इसमें अवांछित संग्रह शामिल नहीं हैं, और जब मैं उत्पन्न फ़ाइलों का पुनर्निर्माण करता हूं, तो मैं अपने परिवर्तनों को नहीं खोता ...


3
न्यूटन JSON
Aizen

21

.NET Core 1.0 में, आप इसे अपनी स्टार्टअप.cs फ़ाइल में एक वैश्विक सेटिंग के रूप में सेट कर सकते हैं:

using System.Buffers;
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;

// beginning of Startup class

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options =>
        {
            options.OutputFormatters.Clear();
            options.OutputFormatters.Add(new JsonOutputFormatter(new JsonSerializerSettings(){
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            }, ArrayPool<char>.Shared));
        });
    }

लेकिन इस मामले में, अगर मैं यह जानना चाहता हूं कि इस संपत्ति को नजरअंदाज किया जाता है तो मुझे कोई अपवाद नहीं मिलेगा।
मेयर स्पिट्जर

10

यदि आप .NET Core 2.x का उपयोग कर रहे हैं, तो स्टार्टअप में अपने ConfigureServices अनुभाग को अपडेट करें

https://docs.microsoft.com/en-us/ef/core/querying/related-data#related-data-and-serialization

    public void ConfigureServices(IServiceCollection services)
    {
    ...

    services.AddMvc()
        .AddJsonOptions(
            options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );

    ...
    }

यदि आप MVC के बिना .NET Core 3.x का उपयोग कर रहे हैं, तो यह होगा:

services.AddControllers()
  .AddNewtonsoftJson(options =>
      options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
   );

यदि आप एंटिटी फ्रेमवर्क और डेटाबेस-प्रथम डिज़ाइन पैटर्न का उपयोग कर रहे हैं तो यह संदर्भ लूप हैंडलिंग लगभग अनिवार्य है।


2
क्या होगा अगर मैं उपयोग न करें services.AddMvc()?
प्रिसर

2
क्या यह एक बुरा अभ्यास है?
रेनन कोल्हो

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

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

9

जब आप पाश मुद्दा है, तो हमें NEWTONSOFTJSON की धारावाहिक बनाने के लिए, मेरे मामले में मुझे Global.asax या apiconfig को संशोधित करने की आवश्यकता नहीं थी। मैं सिर्फ लूपिंग हैंडलिंग को अनदेखा करते हुए JsonSerializesSettings का उपयोग करता हूं।

JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var lst = db.shCards.Where(m => m.CardID == id).ToList();
string json = JsonConvert.SerializeObject(lst, jss);

1
अगर कोई अन्य व्यक्ति एक लाइनर के लिए घड़ी की खिड़की में जाने के लिए यहाँ आया है तो यह पाठ खोजने योग्य है:Newtonsoft.Json.JsonConvert.SerializeObject(objToSerialize, new Newtonsoft.Json.JsonSerializerSettings() {ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore});
ग्राहम

8

हम सेल्फ रेफरेंसिंग लूप को निष्क्रिय करने के लिए इन दोनों लाइनों को DbContext क्लास कंस्ट्रक्टर में जोड़ सकते हैं

public TestContext()
        : base("name=TestContext")
{
    this.Configuration.LazyLoadingEnabled = false;
    this.Configuration.ProxyCreationEnabled = false;
}

यह सबसे सरल में से एक है और आकर्षण की तरह काम कर रहा है । वोट दिया, बहुत-बहुत धन्यवाद ...
मूरत येल्ड्ज़

जैसा कि मैंने दूसरे प्रश्न में लिखा है: मुझे इस तरह के उत्तर पसंद नहीं हैं क्योंकि आप ईएफ 6 की एक विशेषता को बंद कर रहे हैं जो डिफ़ॉल्ट रूप से सक्षम है और कोड का यह टुकड़ा कार्यक्रम के अन्य भागों को तोड़ सकता है। आपको यह समझाना चाहिए कि यह क्या करता है और किस तरह के नतीजे हैं।
एल मैक

@ElMac आप सही हैं, लेकिन अगर हमें उस सुविधा की आवश्यकता नहीं है, तो इस समाधान का उपयोग क्यों नहीं किया जा सकता है?
संजय निषाद

@SanjayNishad मुझे इस बात से ऐतराज नहीं है कि आपको फीचर की जरूरत नहीं है। यह केवल उन उपयोगकर्ताओं के बारे में है जो नहीं जानते कि वे क्या अक्षम कर रहे हैं।
एल मैक

6

आप संपत्ति के लिए एक विशेषता भी लागू कर सकते हैं। [JsonProperty( ReferenceLoopHandling = ... )]विशेषता अच्छी तरह से यह करने के लिए अनुकूल है।

उदाहरण के लिए:

/// <summary>
/// Represents the exception information of an event
/// </summary>
public class ExceptionInfo
{
    // ...code omitted for brevity...

    /// <summary>
    /// An inner (nested) error.
    /// </summary>
    [JsonProperty( ReferenceLoopHandling = ReferenceLoopHandling.Ignore, IsReference = true )]
    public ExceptionInfo Inner { get; set; }

    // ...code omitted for brevity...    
}

आशा है कि मदद करता है, जान


4

लूप संदर्भों को अनदेखा करने और MVC 6 में विश्व स्तर पर उन्हें क्रमबद्ध नहीं करने के लिए स्टार्टअप में निम्न का उपयोग करें।

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().Configure<MvcOptions>(options =>
        {
            options.OutputFormatters.RemoveTypesOf<JsonOutputFormatter>();
            var jsonOutputFormatter = new JsonOutputFormatter();
            jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            options.OutputFormatters.Insert(0, jsonOutputFormatter);
        });
    }

2

WebApiConfig.csकक्षा में इसका उपयोग करें :

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);

2

मेरे लिए मुझे एक अलग मार्ग पर जाना था। JSON.Net धारावाहिक को ठीक करने की कोशिश करने के बजाय मुझे अपने डेटासोनटेक्स्ट पर आलसी लोडिंग के बाद जाना पड़ा।

मैंने इसे अपने आधार भंडार में जोड़ा:

context.Configuration.ProxyCreationEnabled = false;

"संदर्भ" ऑब्जेक्ट एक कंस्ट्रक्टर पैरामीटर है जिसका उपयोग मैं अपने बेस रिपॉजिटरी में करता हूं क्योंकि मैं निर्भरता इंजेक्शन का उपयोग करता हूं। आप कहीं भी अपने डेटाकोटेक्स्ट को पलटने के लिए कहीं भी आप ProxyCreationEnabled संपत्ति को बदल सकते हैं।

http://techie-tid-bits.blogspot.com/2015/09/jsonnet-serializer-and-error-self.html


2

मेरे पास यह अपवाद था और मेरा कार्य समाधान आसान और सरल है,

इसमें JsonIgnore विशेषता जोड़कर संदर्भित संपत्ति को अनदेखा करें:

[JsonIgnore]
public MyClass currentClass { get; set; }

प्रॉपर्टी को रीसेट करें जब आप इसका विवरण दें:

Source = JsonConvert.DeserializeObject<MyObject>(JsonTxt);
foreach (var item in Source)
        {
            Source.MyClass = item;
        }

Newtonsoft.Json का उपयोग करना;


यह मेरी जरूरत का जादू है। इसे हल करें[JsonIgnore]
saviour123

2

टीम:

यह ASP.NET कोर के साथ काम करता है; ऊपर की चुनौती यह है कि आप 'सेटिंग को अनदेखा कैसे करें'। इस बात पर निर्भर करता है कि आपने अपने एप्लिकेशन को कैसे सेटअप किया है यह काफी चुनौतीपूर्ण हो सकता है। यहाँ मेरे लिए क्या काम किया है।

इसे आपके सार्वजनिक शून्य कॉन्फिगर सर्विसेज (IServiceCollection Services) अनुभाग में रखा जा सकता है।

services.AddMvc().AddJsonOptions(opt => 
        { 
      opt.SerializerSettings.ReferenceLoopHandling =
      Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });

2

लोग पहले से ही [JsonIgnore] के बारे में कक्षा में आभासी संपत्ति में शामिल होने की बात कर चुके हैं, उदाहरण के लिए:

[JsonIgnore]
public virtual Project Project { get; set; }

मैं एक अन्य विकल्प भी साझा करूँगा, [JsonProperty (NullValueHandling = NullValueHandling.Ignore)] जो केवल क्रमबद्धता से संपत्ति को छोड़ता है यदि वह शून्य है:

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public virtual Project Project { get; set; }

1

.NET Core 3.0 के लिए, नीचे दिखाए गए अनुसार Startup.cs वर्ग को अपडेट करें।

public void ConfigureServices(IServiceCollection services)
{
...

services.AddControllers()
    .AddNewtonsoftJson(
        options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
    );

...
}

देखें: https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-core-3-0-preview-5/


0

बस Configuration.ProxyCreationEnabled = false;संदर्भ फ़ाइल के अंदर रखें; इससे समस्या का समाधान होगा।

public demEntities()
    : base("name=demEntities")
{
    Configuration.ProxyCreationEnabled = false;
}

0

मेरी समस्या कस्टम विन्यास JsonSerializerSettings के साथ हल:

services.AddMvc(
  // ...
               ).AddJsonOptions(opt =>
                 {
                opt.SerializerSettings.ReferenceLoopHandling =
                    Newtonsoft.Json.ReferenceLoopHandling.Serialize;
                opt.SerializerSettings.PreserveReferencesHandling =
                    Newtonsoft.Json.PreserveReferencesHandling.Objects;
                 });

0

कृपया यह भी सुनिश्चित करें कि आप विधि में प्रतीक्षा और एसिंक्स का उपयोग करें। यदि आपकी वस्तु ठीक से क्रमबद्ध नहीं है, तो आप यह त्रुटि प्राप्त कर सकते हैं।


0

मैं उसी समस्या का सामना कर रहा था और मैंने JsonSetting का उपयोग करके स्वयं-संदर्भित त्रुटि को अनदेखा करने का प्रयास किया, जब तक कि मुझे एक वर्ग नहीं मिला, जो कि आत्म-संदर्भित बहुत गहराई से है और मेरी डॉट-नेट प्रक्रिया Json लेखन मूल्य पर लटकी हुई है।

मेरी समस्या

    public partial class Company : BaseModel
{
    public Company()
    {
        CompanyUsers = new HashSet<CompanyUser>();
    }

    public string Name { get; set; }

    public virtual ICollection<CompanyUser> CompanyUsers { get; set; }
}

public partial class CompanyUser
{
    public int Id { get; set; }
    public int CompanyId { get; set; }
    public int UserId { get; set; }

    public virtual Company Company { get; set; }

    public virtual User User { get; set; }
}

public partial class User : BaseModel
{
    public User()
    {
        CompanyUsers = new HashSet<CompanyUser>();
    }

    public string DisplayName { get; set; }
    public virtual ICollection<CompanyUser> CompanyUsers { get; set; }

}

आप उपयोगकर्ता वर्ग में कंपनीयूज़र के संदर्भ में समस्या देख सकते हैं जो वर्ग जो एक आत्म-संदर्भित है।

अब, मैं GetAll मेथड को कॉल कर रहा हूं जिसमें सभी रिलेशनल गुण शामिल हैं।

cs.GetAll("CompanyUsers", "CompanyUsers.User");

इस स्तर पर मेरी DotNetCore प्रक्रिया निष्पादन JsonResult पर लटकी रहती है, मूल्य लिखती है ... और कभी नहीं आती है। मेरे Start.up में, मैंने पहले ही JsonOption सेट कर दिया है। किसी कारण से EFCore नेस्टेड प्रॉपर्टी में शामिल है, जो मैं Ef को देने के लिए नहीं कह रहा हूं।

    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

अपेक्षित व्यवहार यह होना चाहिए

हे EfCore आप कृपया "CompanyUsers" डेटा के साथ-साथ मेरी कंपनी वर्ग में शामिल कर सकते हैं ताकि मैं आसानी से डेटा तक पहुँच पाऊँ।

फिर

हे EfCore आप "CompanyUsers.User" डेटा को भी शामिल कर सकते हैं ताकि मैं इस Company.CompanyUsers.First () जैसे डेटा तक आसानी से पहुँच सकूँ। User.DisplayName

इस स्तर पर मुझे केवल यह "Company.CompanyUgers.First ()। User.DisplayName" प्राप्त करना चाहिए और इसे मुझे Company.CompanyUsers.First () नहीं देना चाहिए । उपयोगकर्ता.कंपनीउपयोगकर्ता जो स्व-संदर्भ समस्या का कारण बनते हैं ; तकनीकी तौर पर यह मुझे User.CompanyUsers नहीं देना चाहिए क्योंकि CompanyUser एक नेविगेशनल प्रॉपर्टी है। लेकिन, EfCore बहुत उत्साहित है और मुझे User.CompanyUsers दे रहा है ।

इसलिए, मैंने संपत्ति से बाहर निकालने के लिए एक विस्तार विधि लिखने का फैसला किया (यह वास्तव में इसे छोड़कर नहीं है कि यह संपत्ति को शून्य करने के लिए सेट कर रहा है)। इतना ही नहीं यह एरे प्रॉपर्टीज पर भी काम करेगा। नीचे वह कोड है जो मैं अन्य उपयोगकर्ताओं के लिए नगेट पैकेज निर्यात करने के लिए भी जा रहा हूं (यह सुनिश्चित नहीं है कि यह किसी की मदद भी करता है)। कारण सरल है क्योंकि मैं लिखने में बहुत आलसी हूं । चयन (n => नया {n.p1, n.p2}); मैं सिर्फ 1 संपत्ति को बाहर करने के लिए चयन कथन लिखना नहीं चाहता!

यह सबसे अच्छा कोड नहीं है (मैं कुछ चरण में अपडेट करूंगा) जैसा कि मैंने जल्दी में लिखा है और हालांकि यह किसी ऐसे व्यक्ति की मदद कर सकता है जो ऑब्जेक्ट में सरणियों के साथ भी सेट करना चाहता है।

    public static class PropertyExtensions
{
    public static void Exclude<T>(this T obj, Expression<Func<T, object>> expression)
    {
        var visitor = new PropertyVisitor<T>();
        visitor.Visit(expression.Body);
        visitor.Path.Reverse();
        List<MemberInfo> paths = visitor.Path;
        Action<List<MemberInfo>, object> act = null;

        int recursiveLevel = 0;
        act = (List<MemberInfo> vPath, object vObj) =>
        {

            // set last propert to null thats what we want to avoid the self-referencing error.
            if (recursiveLevel == vPath.Count - 1)
            {
                if (vObj == null) throw new ArgumentNullException("Object cannot be null");

                vObj.GetType().GetMethod($"set_{vPath.ElementAt(recursiveLevel).Name}").Invoke(vObj, new object[] { null });
                return;
            }

            var pi = vObj.GetType().GetProperty(vPath.ElementAt(recursiveLevel).Name);
            if (pi == null) return;
            var pv = pi.GetValue(vObj, null);
            if (pi.PropertyType.IsArray || pi.PropertyType.Name.Contains("HashSet`1") || pi.PropertyType.Name.Contains("ICollection`1"))
            {
                var ele = (IEnumerator)pv.GetType().GetMethod("GetEnumerator").Invoke(pv, null);

                while (ele.MoveNext())
                {
                    recursiveLevel++;
                    var arrItem = ele.Current;

                    act(vPath, arrItem);

                    recursiveLevel--;
                }

                if (recursiveLevel != 0) recursiveLevel--;
                return;
            }
            else
            {
                recursiveLevel++;
                act(vPath, pv);
            }

            if (recursiveLevel != 0) recursiveLevel--;

        };

        // check if the root level propert is array
        if (obj.GetType().IsArray)
        {
            var ele = (IEnumerator)obj.GetType().GetMethod("GetEnumerator").Invoke(obj, null);
            while (ele.MoveNext())
            {
                recursiveLevel = 0;
                var arrItem = ele.Current;

                act(paths, arrItem);
            }
        }
        else
        {
            recursiveLevel = 0;
            act(paths, obj);
        }

    }

    public static T Explode<T>(this T[] obj)
    {
        return obj.FirstOrDefault();
    }

    public static T Explode<T>(this ICollection<T> obj)
    {
        return obj.FirstOrDefault();
    }
}

उपरोक्त विस्तार वर्ग आपको स्वयं-संदर्भित लूप को भी सरणियों से बचने के लिए संपत्ति को शून्य करने की क्षमता प्रदान करेगा।

अभिव्यक्ति बिल्डर

    internal class PropertyVisitor<T> : ExpressionVisitor
{
    public readonly List<MemberInfo> Path = new List<MemberInfo>();

    public Expression Modify(Expression expression)
    {
        return Visit(expression);
    }


    protected override Expression VisitMember(MemberExpression node)
    {
        if (!(node.Member is PropertyInfo))
        {
            throw new ArgumentException("The path can only contain properties", nameof(node));
        }

        Path.Add(node.Member);
        return  base.VisitMember(node);
    }
}

उपयोगों:

मॉडल वर्ग

    public class Person
{
    public string Name { get; set; }
    public Address AddressDetail { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public Country CountryDetail { get; set; }
    public Country[] CountryDetail2 { get; set; }
}

public class Country
{
    public string CountryName { get; set; }
    public Person[] CountryDetail { get; set; }
}

प्रतिरूपी डेटा

           var p = new Person
        {
            Name = "Adeel Rizvi",
            AddressDetail = new Address
            {
                Street = "Sydney",
                CountryDetail = new Country
                {
                    CountryName = "AU"
                }
            }
        };

        var p1 = new Person
        {
            Name = "Adeel Rizvi",
            AddressDetail = new Address
            {
                Street = "Sydney",
                CountryDetail2 = new Country[]
                {
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A1" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A2" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A3" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A4" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A5" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A6" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A7" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A8" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A9" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A1" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A2" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A3" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A4" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A5" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A6" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A7" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A8" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A9" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },

                }
            }
        };

मामले:

केस 1: बिना किसी एरे के केवल संपत्ति को छोड़ें

p.Exclude(n => n.AddressDetail.CountryDetail.CountryName);

केस 2: 1 सरणी के साथ संपत्ति को छोड़ दें

p1.Exclude(n => n.AddressDetail.CountryDetail2.Explode().CountryName);

केस 3: 2 नेस्टेड ऐरे के साथ प्रॉपर्टी को छोड़ दें

p1.Exclude(n => n.AddressDetail.CountryDetail2.Explode().CountryDetail.Explode().Name);

केस 4: EF GetAll क्वेरी के साथ शामिल है

var query = cs.GetAll("CompanyUsers", "CompanyUsers.User").ToArray();
query.Exclude(n => n.Explode().CompanyUsers.Explode().User.CompanyUsers);
return query;

आपने देखा है कि एक्सप्लोड () एरे प्रॉपर्टी से संपत्ति प्राप्त करने के लिए हमारी अभिव्यक्ति बिल्डर के लिए भी इसकी एक विस्तार विधि है। जब भी कोई ऐरे प्रॉपर्टी होती है .Explode ()। YourPropertyToExclude और .Explode ()। Property1.MyArrayProperty.Explode ()। MyStupidProetty का उपयोग करें । उपरोक्त कोड सेल्फ-रेफ़रेंसिंग से बचने में मेरी मदद करता है ताकि मैं जितना चाहता हूं उतना गहरा हो। अब मैं GetAll का उपयोग कर सकता हूं और उस संपत्ति को बाहर कर सकता हूं जो मैं नहीं चाहता;

इस बड़ी पोस्ट को पढ़ने के लिए धन्यवाद!


-1

लूपिंग के लिए यह मेरे लिए काम नहीं करता है-
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,

मैंने यह सब यहाँ हल किया है - एंटिटी फ्रेमवर्क बच्चों के साथ .Net कोर 2 वेबएपीआई https://gist.github.com/Kaidanov/f9ad0d79238494432f32b8407942c606

किसी भी टिप्पणी की सराहना करेंगे। हो सकता है कि कोई व्यक्ति इसे कभी भी उपयोग कर सकता है।


-1

C # कोड:

            var jsonSerializerSettings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
                PreserveReferencesHandling = PreserveReferencesHandling.Objects,
            };

            var jsonString = JsonConvert.SerializeObject(object2Serialize, jsonSerializerSettings);

            var filePath = @"E:\json.json";

            File.WriteAllText(filePath, jsonString);

यह अनिवार्य रूप से @ DalSoft के आठ साल पहले के उच्च श्रेणी निर्धारण वाले उत्तर में प्रस्तुत किया गया मार्गदर्शन है, लेकिन बहुत कम स्पष्टीकरण के साथ।
जेरेमी कैनी

आशा है कि यह समस्या को हल कर देगा, लेकिन कृपया इसके साथ अपने कोड की व्याख्या जोड़ें ताकि उपयोगकर्ता को सही समझ मिल जाएगी जिसे वह वास्तव में चाहता है।
जयमिल पटेल

-2

मैं समाधान है कि यह से करता है पसंद आया Application_Start()जवाब में के रूप में यहाँ

जाहिरा तौर पर मैं अपने फ़ंक्शन के भीतर कॉन्फ़िगरेशन का उपयोग करके जावास्क्रिप्ट में जावास्क्रिप्ट ऑब्जेक्ट्स को एक्सेस नहीं कर सका क्योंकि DalSoft के जवाब में ऑब्जेक्ट वापस आ गया था, ऑब्जेक्ट के सभी (कुंजी, वैल) पर "\ n \ r" था।

वैसे भी जो भी कार्य महान है (क्योंकि विभिन्न दृष्टिकोण टिप्पणियों और पूछे गए प्रश्नों के आधार पर अलग-अलग परिदृश्य में काम करते हैं) हालांकि ऐसा करने का एक मानक तरीका दृष्टिकोण का समर्थन करने वाले कुछ अच्छे प्रलेखन के साथ बेहतर होगा।

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