6

Estoy compilando una aplicación usando MVC3, motor Razor view, Repository Pattern with Unit of Work y usando EF4.1 Code First para definir mi modelo de datos.Serialización de entidades EF4.1 usando JSON.Net

Aquí hay un poco de fondo (si no lo quiere, gírelo).

La aplicación en sí es solo un 'Menú' de la Intranet.

Los 2 entidades principales son Menultem y el Departamento de los cuales:

  • Menultem puede tener muchos departamentos
  • Departamentos pueden tener muchos MenuItems
  • Menultem puede tener un Menultem como padre

Así es como he definido mis Entidades

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

Uso FluentAPI para definir la referencia automática Muchos a muchos para MenuItem.

El problema que tengo es pasar un elemento de menú a la vista a través de JSON. Los problemas centrales son que tengo una referencia circular entre mis entidades que el analizador JSON integrado no puede tratar y tengo la carga diferida y la generación de proxy todavía habilitada.

Estoy usando la biblioteca JSON.net de Nuget como mi serializador JSON, ya que parece ser una buena manera de resolver el problema de referencia circular. Ahora no estoy seguro de cómo 'arreglar' el problema de generación de proxy. Actualmente el serializador arroja 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.

¿Alguien puede ayudarme con esto? Si desactivo la generación de proxy, voy a tener muchísimo tiempo cargando todos los elementos de MenuItem, así que estoy interesado en dejar esto. He leído una buena cantidad y parece que hay una variedad de respuestas diferentes, incluyendo la proyección de las entidades en otro objeto y serializar eso, etc. Idealmente, ¿habría alguna forma de configurar JSON.net para ignorar el objeto RelationshipManager?

actualización

Aquí es lo que he usado como un serializador personalizado ContractResolver para JSON.Net. Esto parece haber solucionado mi problema.

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

IEntity es una interfaz todo mi Código primera entidad de objetos implementar.

Respuesta

0

Bueno, que utiliza potente API de serialización, que serializa referencias y todos los miembros, así y ahora se queja de que serializa todos los miembros :)

no he probado, pero creo que esto le traerá cerca de la solución.

JSON.NET es una herramienta bastante poderosa y debe ofrecerle el punto de extensibilidad para evitar este comportamiento, pero deberá codificarlo usted mismo. Necesitará personalizar DataContractResolver donde defina qué miembros se deben serializar. Here es el ejemplo similar de NHibernate.

Puede implementar un poco de lógica que solo tomará miembros presentes en la clase padre del proxy dinámico. Espero que esto no rompa la carga floja.Para validar que la entidad actual es de proxy puede utilizar este código para obtener todos los tipos de proxy conocidos:

IEnumerable<Type> types = ((IObjectContextAdapter)dbContext).ObjectContext.GetKnownProxyTypes(); 
+0

Gracias Ladislav. De su publicación de blog referenciada, pude escribir un 'ContractResolver' personalizado para especificar qué miembros, y más específicamente qué tipos de objetos, resulta ser serializar. En algunos casos, se estaba transfiriendo un objeto de framework para ser serializado, así que tuve que verificar el tipo de objeto. Actualizaré mi pregunta con el código que he usado. Siéntase libre de comentar al respecto :) –

2

que realizar esta pregunta tiene una respuesta aceptada, pero pensé que iba a publicar mi código de EF La primera solución para los futuros espectadores. Yo era capaz de moverse por el mensaje de error con el sistema de resolución de contrato a continuación:

class ContractResolver : DefaultContractResolver 
{ 
     protected override List<System.Reflection.MemberInfo> GetSerializableMembers(Type objectType) 
     { 
      if (objectType.Namespace.StartsWith("System.Data.Entity.Dynamic")) 
      { 
       return base.GetSerializableMembers(objectType.BaseType); 
      } 

      return base.GetSerializableMembers(objectType); 
     } 
} 

Esto funciona porque Código EF primeras clases heredan de la clase POCO que en realidad se quiere serializado, así que si podemos identificar cuando estamos ante una clase generada por EF (al verificar el espacio de nombres) podemos simplemente serializar usando las propiedades de la clase base, y por lo tanto, solo serializar las propiedades de POCO que realmente buscamos en primer lugar.

+1

Encontré que necesita probar objectType! = Null && objectType.Namespace! = Null –

+0

@TonyOHagan absolutamente - siempre debe anular la comprobación de los parámetros. Los dejé aquí por brevedad –

Cuestiones relacionadas