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