5

JSON Serialization (ASP.Net Web API) fails because of self-referencing loop (it’s a common problem, Reason: an entity being requested lazy loads child entities and every child has a back reference to parent entity).

Work around I found, but doesn’t help me:

  1. Use [JsonIgnore] for navigation properties to be ignored: This solution works but doesn’t apply in my case. For Example: To get a Customer information along with his Orders, I would quickly add [JsonIgnore] to Customer property in Order class, but when I want to get an Order information along with the Customer details, since there’s [JsonIgnore] on Customer property, it won’t include Customer details.
  2. Change JSON.Net Serializer Settings to Preserve References: Can’t Preserve because I don’t need Circular referenced data.
  3. Disable Proxy Creation at the Data Context and use explicit loading(this should ideally solve the problem): Disabling proxy creation stops Lazy Loading and returns data without error, but when I explicitly Include child entities, I again the get the unexpected self-referencing loop error! The error is at the back-reference level to parent entity.

Any experiences along the same lines/suggestions?

4

3 回答 3

3

我尝试了所有建议的解决方案,但没有奏效。最后将 JSON.Net 序列化程序的 DefaultContractResolver 覆盖为:

public class FilterContractResolver : DefaultContractResolver
{
    Dictionary<Type, List<string>> _propertiesToIgnore;

    public FilterContractResolver(Dictionary<Type, List<string>> propertiesToIgnore)
    {
        _propertiesToIgnore = propertiesToIgnore;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        List<string> toIgnore;
        property.Ignored |= ((_propertiesToIgnore.TryGetValue(member.DeclaringType, out toIgnore) || _propertiesToIgnore.TryGetValue(member.DeclaringType.BaseType, out toIgnore)) && toIgnore.Contains(property.PropertyName));
        return property;
    }
}

然后创建一个静态类,它根据控制器返回要忽略的属性字典:

public static class CriteriaDefination
{
    private static Dictionary<string, Dictionary<Type, List<string>>> ToIgnore = new Dictionary<string, Dictionary<Type, List<string>>>
    {
        {
            "tblCustomer", new Dictionary<Type, List<string>>{
                {
                    typeof(tblCustomer), new List<string>{
                        //include all
                    }
                },
                {
                    typeof(tblOrder), new List<string>{
                        "tblCustomer"//ignore back reference to tblCustomer
                    }
                }
            }
        },
        {
            "tblOrder", new Dictionary<Type, List<string>>{
                {
                    typeof(tblCustomer), new List<string>{
                        "tblOrders"//ignore back reference to tblOrders
                    }
                },
                {
                    typeof(tblOrder), new List<string>{
                        //include all
                    }
                }
            }
        }
    };
    public static Dictionary<Type, List<string>> IgnoreList(string key)
    {
        return ToIgnore[key];
    }
}

在每个控制器内部更改 JSON 格式化程序,例如:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new FilterContractResolver(CriteriaDefination.IgnoreList("tblCustomer"));
于 2013-06-12T10:37:27.123 回答
2

这就是我最终解决的问题,希望它可以帮助其他人。

假设 EF 类的结构如下:

public partial class MyEF
{
  public virtual ICollection<MyOtherEF> MyOtherEFs {get; set;}
}
public partial class MyOtherEF
{
  public virtual MyEF MyEF {get; set;}
}

要在 JSON.NET 中保持序列化形式,您可以扩展该类并添加一个名称为“ShouldSerialize”+ 属性名称的方法,如下所示:

public partial class MyEF
{
  public bool ShouldSerializeMyOtherEFs() { return false; }
}

如果您想更花哨,可以在方法中添加逻辑,以便在某些情况下可以序列化。这允许您将序列化逻辑排除在 EF Model First 代码创建之外,只要此代码位于不同的物理代码文件中。

于 2013-08-13T03:33:48.820 回答
1

不要让实体框架生成模型,而是将 Code First 与现有数据库一起使用。现在你更有控制力了。

请参阅 Scott Guthrie 的此博客条目

于 2013-06-07T14:06:11.220 回答