当使用显式Include时,即使在ProxyCreation为false之后,也会出现JSON序列化实体框架自我引用循环



JSON序列化. Net Web API)由于自引用循环而失败(这是一个常见的问题,原因:被请求的实体延迟加载子实体,并且每个子实体都有对父实体的反向引用)。

Work around I found, but not help me:

  1. 使用[JsonIgnore]来忽略导航属性:这个解决方案有效,但不适用于我的情况。例如:为了获得客户信息以及他的订单,我会快速将[JsonIgnore]添加到订单类中的客户属性,但是当我想获得订单信息以及客户详细信息时,因为在客户属性上有[JsonIgnore],所以它不会包括客户详细信息。
  2. 改变JSON。保留引用的Net序列化器设置:不能保存,因为我不需要循环引用数据。
  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"));

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

假设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代码创建之外,只要该代码位于不同的物理代码文件中。

与其让实体框架生成模型,不如使用现有数据库的"代码优先"。现在你更能控制自己了。

查看Scott Guthrie的博客条目

相关内容

  • 没有找到相关文章

最新更新