2009-03-18 32 views
43

Parece que la serialización de objetos de Entity Framework en JSON no es posible utilizando el DataContractJsonSerializer nativo de WCF o el serializador de JavaScript nativo de ASP.NET. Esto se debe a los problemas de conteo de referencias que rechazan ambos serializadores. También probé Json.NET, que también falla específicamente en un problema de recuento de referencias.Serializar objetos de Entity Framework en JSON


Editar: Json.NET puede ahora serialize and deserialize Entity Framework entities.


Mis objetos son objetos de Entity Framework, que están sobrecargados para llevar a cabo la funcionalidad del negocio adicional (por ejemplo. Autenticación, etc.) y que no quieren decorar estas clases con atributos específicos de la plataforma, etc. como yo quiero presentar una API agnóstica de plataforma

De hecho, he blog acerca de los pasos individuales que fui aunque a https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-solution/

¿Me he perdido algo obvio?

+0

Sí JSon.NET serialize pero me gustaría devolver IQueryable no json string! Si fuera devuelto IQueryable podría utilizar OData. –

+0

Enlace en bloggingabout.net. Está roto –

+0

@MichaelFreidgeim Sí, me di cuenta de esto cuando alguien borró otra publicación. Lo cual fue agradable Parece que el blog decidió eliminar mi blog. No feliz. Solo puedo disculparme. Me he tomado el tiempo para mirar hacia atrás en los archivos de Internet y volver a publicar en una ubicación diferente. –

Respuesta

71

La manera en que lo hago es proyectando los datos que deseo serializar en un tipo anónimo y serialándolos. Esto asegura que solo la información que realmente quiero en el JSON está serializada, y no serializo inadvertidamente algo más abajo en el gráfico del objeto. Se ve así:

var records = from entity in context.Entities 
       select new 
       { 
        Prop1 = entity.Prop1, 
        Prop2 = entity.Prop2, 
        ChildProp = entity.Child.Prop 
       } 
return Json(records); 

Encuentro tipos anónimos ideales para esto. El JSON, obviamente, no importa qué tipo se usó para producirlo. Y los tipos anónimos le brindan flexibilidad completa en cuanto a qué propiedades y estructura pone en el JSON.

+2

gracias por esto, ¡he estado navegando durante horas en esto! – Peter

+1

Excelente solución. ¿Existe alguna forma viable de deserializar un objeto javascript en un objeto EF? –

+0

Samuel, el encuadernador de modelo predeterminado generalmente puede hacer frente a los tipos de EF. Pero prefiero deserializarme a un modelo específico de edición, luego asignarme al tipo EF. –

17

Microsoft cometió un error en la forma en que hacían los objetos EF en contratos de datos. Incluyeron las clases base y los enlaces de atrás.

Lo mejor que puede hacer es crear clases de objetos de transferencia de datos equivalentes para cada una de las entidades que desea devolver. Estos incluirían solo los datos, no el comportamiento, y no las partes específicas de EF de una entidad. También crearía métodos para traducir hacia y desde sus clases de DTO.

Sus servicios devolverían los objetos de transferencia de datos.

+0

Ahora hay una opción para hacer que la serialización sea unidireccional. Es posible que esa opción no existiera cuando hiciste esta publicación. Solo pensé en agregarlo en caso de que otros se enteren de esto en el futuro. – Yuck

+12

@Yuck: agregue un enlace a la información sobre esta función, por favor. –

+0

Por lo que sé, EF no tiene esa configuración. Esto es solo para Linq-to-SQL. – Ziad

1

Una solución más si desea tener una mejor consistencia del código es usar JavaScriptConverter, que manejará las dependencias de referencia circulares y no serializará dichas referencias.

He blog acerca aquí:

http://hellowebapps.com/2010-09-26/producing-json-from-entity-framework-4-0-generated-classes/

+1

Estoy de acuerdo Mehal. Extendí su ejemplo para manejar algunos otros casos en mi respuesta aquí http://stackoverflow.com/questions/4053161/serializing-entity-framework-problems –

+0

Deseo que este código funcione ... – jocull

+0

El enlace está roto –

2

Mi solución era simplemente eliminar la referencia de los padres en mis entidades secundarias.

Así que en mi modelo, seleccioné la relación y cambié la referencia principal para que fuera interna en lugar de pública.

Puede que no sea una solución ideal para todos, pero funcionó para mí.

+0

¡Parece que funciona bastante bien! – Farinha

1

FYI He encontrado una solución alternativa

Puede establecer la relación padre como confidenciales de modo a continuación, las propiedades no están expuestos durante la traducción de retirar el bucle infinito propiedad

1

Luché con este problema desde hace días,

Solución. Dentro de tu ventana de edmx - haga clic derecho y añadir el código del artículo generación - Seleccione la pestaña Código - seleccione EF 4x.POCOC Entidad Generador

Si no lo ve, entonces usted tendrá que instalar con Nuget, búsqueda EF.

El generador de Entidades generará todo su tipo de objeto complejo y entidad en clases simples para serializar en json.

1

Lo resolví obteniendo solo tipos de objetos del espacio de nombres del sistema, y ​​luego los convertí a Diccionario y luego los agregué a la lista. Funciona bien para mí :)

Parece complicado, pero esta fue la única solución genérica que funcionó para mí ... Estoy usando esta lógica para un ayudante que estoy creando, por lo que es para un uso especial donde Necesito poder interceptar cada tipo de objeto en el objeto de entidad, tal vez alguien podría adaptarlo a su uso.

List<Dictionary<string, string>> outputData = new List<Dictionary<string, string>>(); 

// convert all items to objects 
var data = Data.ToArray().Cast<object>().ToArray(); 

// get info about objects; and get only those we need 
// this will remove circular references and other stuff we don't need 
PropertyInfo[] objInfos = data[0].GetType().GetProperties(); 
foreach (PropertyInfo info in objInfos) { 
    switch (info.PropertyType.Namespace) 
    { 
      // all types that are in "System" namespace should be OK 
      case "System": 
       propeties.Add(info.Name); 
       break; 
    } 
} 
Dictionary<string, string> rowsData = null; 
foreach (object obj in data) { 
    rowsData = new Dictionary<string, string>(); 
    Type objType = obj.GetType(); 
    foreach (string propertyName in propeties) 
    { 
//if You don't need to intercept every object type You could just call .ToString(), and remove other code 
     PropertyInfo info = objType.GetProperty(propertyName); 
     switch(info.PropertyType.FullName) 
     { 
       case "System.String": 
        var colData = info.GetValue(obj, null); 
        rowsData.Add(propertyName, colData != null ? colData.ToString() : String.Empty); 
        break; 
//here You can add more variable types if you need so (like int and so on...) 
      } 
     } 

     outputData .Add(rowsData); // add a new row 
} 

"datosSalida" es seguro para codificar JSON ... Esperanza alguien va a encontrar esta solución útil. Fue divertido escribirlo :)

2

Basado en @Craig Stuntz answer y similar a un DTO, para mi solución he creado una clase parcial del modelo (en un archivo separado) y un método de devolución de objetos con la forma en que quiero usar solo las propiedades que serán necesarias.

namespace TestApplication.Models 
{ 
    public partial class Employee 
    { 
     public object ToObject() 
     { 
      return new 
      { 
       EmployeeID = EmployeeID, 
       Name = Name, 
       Username = Username, 
       Office = Office, 
       PhoneNumber = PhoneNumber, 
       EmailAddress = EmailAddress, 
       Title = Title, 
       Department = Department, 
       Manager = Manager 
      }; 
     } 
    } 
} 

Y entonces me llaman simplemente en mi regreso:

var employee = dbCtx.Employees.Where(x => x.Name == usersName).Single(); 
return employee.ToObject(); 

creo que la respuesta aceptada es más rápido y fácil, sólo tiene que utilizar mi método para mantener a todos mis retornos consistentes y seco.

Cuestiones relacionadas