Json and Circular Reference Exception

前端 未结 9 1387
挽巷
挽巷 2020-11-27 03:17

I have an object which has a circular reference to another object. Given the relationship between these objects this is the right design.

To Illustrate

相关标签:
9条回答
  • 2020-11-27 03:48

    You need to decide which is the "root" object. Say the machine is the root, then the customer is a sub-object of machine. When you serialise machine, it will serialise the customer as a sub-object in the JSON, and when the customer is serialised, it will NOT serialise it's back-reference to the machine. When your code deserialises the machine, it will deserialise the machine's customer sub-object and reinstate the back-reference from the customer to the machine.

    Most serialisation libraries provide some kind of hook to modify how deserialisation is performed for each class. You'd need to use that hook to modify deserialisation for the machine class to reinstate the backreference in the machine's customer. Exactly what that hook is depends on the JSON library you are using.

    0 讨论(0)
  • 2020-11-27 03:58

    Based on txl's answer you have to disable lazy loading and proxy creation and you can use the normal methods to get your data.

    Example:

    //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 讨论(0)
  • 2020-11-27 04:02

    What I have done is a bit radical, but I don't need the property, which makes the nasty circular-reference-causing error, so I have set it to null before serializing.

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

    If you really need your properties, you can create a viewmodel which does not hold circular references, but maybe keeps some Id of the important element, that you could use later for restoring the original value.

    0 讨论(0)
  • 2020-11-27 04:03

    Use to have the same problem. I have created a simple extension method, that "flattens" L2E objects into an IDictionary. An IDictionary is serialized correctly by the JavaScriptSerializer. The resulting Json is the same as directly serializing the object.

    Since I limit the level of serialization, circular references are avoided. It also will not include 1->n linked tables (Entitysets).

        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);
        }
    

    My Action method looks like this:

        public JsonResult AsJson(int id) {
            var data = Find(id);
            var result = this.JsonFlatten(data);
            return Json(result, JsonRequestBehavior.AllowGet);
        }
    
    0 讨论(0)
  • 2020-11-27 04:09

    In the Entity Framework version 4, there is an option available: ObjectContextOptions.LazyLoadingEnabled

    Setting it to false should avoid the 'circular reference' issue. However, you will have to explicitly load the navigation properties that you want to include.

    see: http://msdn.microsoft.com/en-us/library/bb896272.aspx

    0 讨论(0)
  • 2020-11-27 04:09

    I've had the same problem this week as well, and could not use anonymous types because I needed to implement an interface asking for a List<MyType>. After making a diagram showing all relationships with navigability, I found out that MyType had a bidirectional relationship with MyObject which caused this circular reference, since they both saved each other.

    After deciding that MyObject did not really need to know MyType, and thereby making it a unidirectional relationship this problem was solved.

    0 讨论(0)
提交回复
热议问题