Сериализовать объекты Entity Framework в JSON

Кажется, что сериализация объектов Entity Framework в JSON невозможна с использованием встроенного в WCF DataContractJsonSerializer или собственного сериализатора кода ASP.NET. Это связано с проблемами подсчета ссылок, которые отклоняются как сериализаторы. Я также попробовал Json.NET, который также не работает конкретно по проблеме подсчета ссылок.


Изменить: Теперь Json.NET может сериализовать и десериализовать сущности Entity Framework.


Мои объекты - объекты Entity Framework, которые перегружены для выполнения дополнительных бизнес-функций (например, аутентификация и т.д.), и я не хочу украшать эти классы атрибутами платформы и т.д., поскольку я хочу представить платформу -агностический API.

Я действительно писал об отдельных шагах, которые я прошел, хотя в https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-solution/

Я пропустил что-то очевидное?

Ответ 1

Как я это делаю, проецируя данные, которые я хочу сериализовать в анонимный тип, и сериализуя это. Это гарантирует, что только информация, которую я действительно хочу в JSON, сериализуется, и я не случайно сериализую что-то дальше по графику объекта. Это выглядит так:

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

Я считаю анонимные типы идеальными для этого. Очевидно, JSON не волнует, какой тип был использован для его создания. А анонимные типы дают вам полную гибкость в отношении того, какие свойства и структура вы вкладываете в JSON.

Ответ 2

Microsoft допустила ошибку в том, как они превратили объекты EF в контракты данных. Они включали базовые классы и обратные ссылки.

Лучше всего создать эквивалентные классы объектов передачи данных для каждого из объектов, которые вы хотите вернуть. Они будут включать только данные, а не поведение, а не EF-специфические части объекта. Вы также должны создавать методы для перевода на классы DTO и из них.

Затем ваши службы возвратят объекты передачи данных.

Ответ 3

Моим решением было просто удалить родительскую ссылку на дочерние объекты.

Итак, в моей модели я выбрал связь и изменил ссылку "Родитель" как "Внутренний", а не "Публичный".

Не может быть идеальным решением для всех, но работал у меня.

Ответ 4

Основываясь на ответе @Craig Stuntz и подобном DTO, для моего решения я создал частичный класс модели (в отдельном файле) и метод возвращаемого объекта с тем, как я хочу, используя только свойства, которые будут необходимо.

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

И затем я называю это просто по возвращении:

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

Я думаю, что принятый ответ более быстрый и легкий, я просто использую свой метод, чтобы сохранить все мои результаты согласованными и сухими.

Ответ 5

Еще одно решение, если вы хотите улучшить согласованность кода, - это использовать JavaScriptConverter, который будет обрабатывать циклические ссылочные зависимости и не будет сериализовать такие ссылки.

Я писал о нем здесь:

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

Ответ 6

FYI Я нашел альтернативное решение

Вы можете установить родительское отношение как личное, чтобы затем свойства не отображались во время перевода, удалив бесконечный цикл свойств

Ответ 7

Я боролся с этой проблемой в течение нескольких дней,

Решение. Внутри окна edmx. - щелкните правой кнопкой мыши и добавьте элемент генерации кода - Выберите вкладку "Код" - выберите EF 4x.POCOC Entity Generator

Если вы его не видите, вам нужно будет установить его с помощью nuget, search EF.

Генератор Entity будет генерировать весь сложный тип и объект объекта в простые классы для сериализации в json.

Ответ 8

Я решил это, получив только типы объектов из пространства имен System, а затем преобразую их в словарь и затем добавлю их в список. Хорошо работает для меня:)

Это выглядит сложным, но это было единственное общее решение, которое сработало для меня... Я использую эту логику для помощника, который я создаю, поэтому для особого использования, когда мне нужно перехватывать каждый тип объекта в объекте сущности, возможно, кто-то может адаптировать его к его использованию.

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" безопасен для кодирования JSON... Надеюсь, кто-то найдет это решение полезным. Было весело писать:)