使用JSON.Net序列化EF4.1实体

Mat*_*ler 6 serialization json.net entity-framework-4 jsonresult asp.net-mvc-3

我正在使用MVC3,Razor视图引擎,使用工作单元的存储库模式构建应用程序,并使用EF4.1 Code First来定义我的数据模型.

这里有一些背景(如果你想要的话就会有光泽).

应用程序本身只是一个Intranet"菜单".

2个主要实体是MenuItem和Department,其中:

  • MenuItem可以有许多部门
  • 部门可以有许多MenuItem
  • MenuItem可以将MenuItem作为父项

这就是我定义我的实体的方式

public class MenuItem
{
   public int MenuItemId { get; set; }
   public string Name { get; set; }
   public string Url { get; set; }
   public virtual ICollection<Department> Departments { get; set; }
   public int? ParentId { get; set; }
   public virtual MenuItem ParentMenuItem { get; set; }
}

public class Department
{
   public int DepartmentId { get; set; }
   public string Name { get; set; }
   public virtual ICollection<MenuItem> MenuItems { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用FluentAPI为MenuItem定义多对多的自引用.

我遇到的问题是通过JSON将MenuItem传递给视图.中心问题是我的实体之间有一个循环引用,内置的JSON解析器无法处理,我仍然启用了延迟加载和代理生成.

我使用Nuget的JSON.net库作为我的JSON Serializer,因为这似乎是循环引用问题的一个很好的方法.我现在不确定如何"修复"代理生成问题.目前序列化器抛出The RelationshipManager object could not be serialized. This type of object cannot be serialized when the RelationshipManager belongs to an entity object that does not implement IEntityWithRelationships.

谁能帮我这个?如果我关闭代理生成,我将有一段时间加载所有的MenuItem孩子,所以我很想留下这个.我已经阅读了相当多的数据,似乎有各种不同的答案,包括将实体投影到另一个对象并序列化等等.理想情况下,有一些方法可以配置JSON.net来忽略RelationshipManager对象?

更新

这是我用作JSON.Net序列化程序的Custom ContractResolver的内容.这似乎解决了我的问题.

public class ContractResolver : DefaultContractResolver
{
    private static readonly IEnumerable<Type> Types = GetEntityTypes();
    private static IEnumerable<Type> GetEntityTypes()
    {
        var assembly = Assembly.GetAssembly(typeof (IEntity));
        var types = assembly.GetTypes().Where(t => String.Equals(t.Namespace, "Namespace", StringComparison.Ordinal));
        return types;
    }

    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        if (!AllowType(objectType))
            return new List<MemberInfo>();

        var members = base.GetSerializableMembers(objectType);
        members.RemoveAll(memberInfo => (IsMemberEntityWrapper(memberInfo)));
        return members;
    }

    private static bool AllowType(Type objectType)
    {
        return Types.Contains(objectType) || Types.Contains(objectType.BaseType);
    }

    private static bool IsMemberEntityWrapper(MemberInfo memberInfo)
    {
        return memberInfo.Name == "_entityWrapper";
    }
}
Run Code Online (Sandbox Code Playgroud)

IEntity 是我的所有Code First实体对象实现的接口.

Lad*_*nka 0

好吧,您使用了强大的序列化 API,它还序列化了引用和所有成员,现在您抱怨它序列化了所有成员:)

我没有测试它,但我相信这会让您接近解决方案。

JSON.NET 是非常强大的工具,它应该为您提供可扩展点来避免这种行为,但您必须自己编写代码。您将需要自定义DataContractResolver来定义应序列化哪些成员。是 NHibernate 的类似示例。

您可以实现一些逻辑,该逻辑仅采用动态代理父类中存在的成员。我希望这不会破坏延迟加载。要验证当前实体是代理,您可以使用此代码来获取所有已知的代理类型:

IEnumerable<Type> types = ((IObjectContextAdapter)dbContext).ObjectContext.GetKnownProxyTypes();
Run Code Online (Sandbox Code Playgroud)