2009-03-18 3 views
43

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


Edit: Json.NET может теперь serialize and deserialize Entity Framework entities.


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

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

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

+0

Да JSon.NET сериализуется, но я хотел бы вернуть IQueryable не json string! Если бы я вернулся IQueryable Я мог бы использовать OData. –

+0

Ссылка на bloggingabout.net. Разбито –

+0

@MichaelFreidgeim Да, я понял это, когда кто-то удалил еще одну запись. Это было хорошо. Кажется, что блог решил удалить мой блог. Не счастлив. Я могу только извиниться. Я нашел время, чтобы оглянуться на интернет-архивы и опубликовать их в другом месте. –

ответ

71

Как я это делаю, проецируя данные, которые я хочу сериализовать в анонимный тип, и сериализуя это. Это гарантирует, что только информация, которую я действительно хочу в 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

спасибо за это, я проработал часами на этом! – Peter

+1

Отличное решение. Существует ли жизнеспособный способ десериализации объекта javascript обратно в объект EF? –

+0

Самуэль, связующее устройство по умолчанию может в целом справляться с типами EF. Но я предпочитаю десериализовать модель редактирования, а затем сопоставляю ее с типом EF. –

17

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

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

После этого ваши службы будут возвращать объекты передачи данных.

+0

Теперь есть возможность сделать сериализацию однонаправленной. Возможно, этот вариант не существовал, когда вы делали этот пост. Просто подумал, что я добавлю его, если другие встретят это в будущем. – Yuck

+12

@Yuck: добавьте ссылку на информацию об этой функции, пожалуйста. –

+0

Насколько я знаю, EF не имеет такой настройки. Это только для Linq-to-SQL. – Ziad

1

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

Я уже писал о здесь:

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

+1

Я согласен с Mehal. Я продлил ваш пример, чтобы обработать некоторые другие случаи в моем ответе здесь http://stackoverflow.com/questions/4053161/serializing-entity-framework-problems –

+0

Желаю, чтобы этот код работал ... – jocull

+0

Ссылка была разбита –

2

Мое решение было просто удалить родительскую ссылку на моих дочерних организаций.

Итак, в моей модели я выбрал отношения и изменил ссылку родителя как на внутреннюю, а на общедоступную.

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

+0

Это, похоже, работает очень хорошо! – Farinha

1

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

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

1

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

Решение. Внутри окна edmx. - правая кнопка мыши и добавить код пункт поколения - Выберите вкладку Code - выберите EF 4x.POCOC Entity Генератор

Если вы не видите его, то вам придется установить его с NuGet, поиск EF.

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

1

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

2

Основываясь на ответе @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(); 

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

Смежные вопросы