Serializar objetos de Entity Framework en JSON


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


Editar: Json.NET ahora puede serializar y deserializar entidades de Entity Framework.


Mis objetos son Objetos de Entity Framework, que están sobrecargados para realizar funciones empresariales adicionales(p. ej. autenticación, etc.) y no quiero decorar estas clases con atributos específicos de la plataforma, etc. como quiero presentar una API independiente de la plataforma.

En realidad he blogueado sobre los pasos individuales que seguí en https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-solution /

¿Me he perdido algo obvio?

Author: Program.X, 2009-03-18

8 answers

La forma en que hago esto es proyectando los datos que quiero serializar en un tipo anónimo y serializándolos. Esto asegura que solo la información que realmente quiero en el JSON sea serializada, y no serializo inadvertidamente algo más abajo en el gráfico de objetos. 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 casi ideales para esto. Al JSON, obviamente, no le importa qué tipo se usó para producirlo. Y los tipos anónimos le dan una flexibilidad completa en cuanto a lo que propiedades y estructura que pones en el JSON.

 71
Author: Craig Stuntz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-18 12:30:06

Microsoft cometió un error en la forma en que convirtieron los objetos EF en contratos de datos. Incluyeron las clases base y los enlaces posteriores.

Su mejor apuesta será 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 DTO.

Sus servicios devolverían la Transferencia de Datos Objeto.

 16
Author: John Saunders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-18 12:16:06

Mi solución fue simplemente eliminar la referencia padre en mis entidades hijas.

Así que en mi modelo, seleccioné la relación y cambié la referencia Padre para que fuera Interna en lugar de Pública.

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

 2
Author: Anthony Main,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-23 12:05:51

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 return object con cómo lo quiero usando solo las propiedades que se necesitarán.

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 luego lo llamo simplemente en mi retorno:

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

Creo que la respuesta aceptada es más rápida y fácil, solo uso mi método para mantener todas mis devoluciones consistentes y SECAS.

 2
Author: Pat Migliaccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-10 17:50:32

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

He blogueado sobre esto:

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

 1
Author: Mehal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-26 14:53:35

Para su información, encontré una solución alternativa

Puede establecer la relación padre como privada para que las propiedades no se expongan durante la traducción eliminando el bucle de propiedades infinitas

 1
Author: Anthony Main,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-28 10:10:32

Luché con este problema durante días,

Solución. Dentro de tu ventana de edmx. - haga clic derecho y añadir elemento de generación de código - Seleccione la pestaña de código - seleccione EF 4x. POCOC Entity Generator

Si no lo ves, entonces tendrás que instalarlo con nuget, buscar EF.

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

 1
Author: Tebza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-24 13:35:01

Lo resolví obteniendo solo tipos de objetos del espacio de nombres del sistema, y luego los convertí en Diccionario y luego los agregé 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 haciendo, por lo que es para un uso especial donde necesito ser capaz de interceptar cada tipo de objeto en 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
}

"outputData" es seguro para la codificación JSON... Esperar alguien encontrará esta solución útil. Fue divertido escribirlo :)

 1
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-03 13:02:03