EF 4.1 – Code First – Ошибка серийной ссылки JSON

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

Это ошибка:

ошибка

Круговая ссылка была обнаружена при сериализации объекта типа «System.Data.Entity.DynamicProxies.Order_83CECF2AA4DE38232F9077D4B26941AB96BC61230419EA8AC42C9100E6072812». Описание: Необработанное исключение возникло во время выполнения текущего веб-запроса. Просмотрите трассировку стека для получения дополнительной информации об ошибке и ее возникновении в коде.

Сведения об исключении: System.InvalidOperationException: круговая ссылка была обнаружена при сериализации объекта типа «System.Data.Entity.DynamicProxies.Order_83CECF2AA4DE38232F9077D4B26941AB96BC61230419EA8AC42C9100E6072812».

Ошибка источника:

Необработанное исключение было создано во время выполнения текущего веб-запроса. Информация о происхождении и местоположении исключения может быть идентифицирована с использованием следа стека исключений ниже.

Мои classы:

порядок

public class Order { [Key] public int OrderId { get; set; } public int PatientId { get; set; } public virtual Patient Patient { get; set; } public int CertificationPeriodId { get; set; } public virtual CertificationPeriod CertificationPeriod { get; set; } public int AgencyId { get; set; } public virtual Agency Agency { get; set; } public int PrimaryDiagnosisId { get; set; } public virtual Diagnosis PrimaryDiagnosis { get; set; } public int ApprovalStatusId { get; set; } public virtual OrderApprovalStatus ApprovalStatus { get; set; } public int ApproverId { get; set; } public virtual User Approver { get; set; } public int SubmitterId { get; set; } public virtual User Submitter { get; set; } public DateTime ApprovalDate { get; set; } public DateTime SubmittedDate { get; set; } public Boolean IsDeprecated { get; set; } } 

Пациент

 public class Patient { [Key] public int PatientId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string MiddleInitial { get; set; } public bool IsMale; public DateTime DateOfBirth { get; set; } public int PatientAddressId { get; set; } public Address PatientAddress { get; set; } public bool IsDeprecated { get; set; } } 

Период сертификации

 public class CertificationPeriod { [Key] public int CertificationPeriodId { get; set; } public DateTime startDate { get; set; } public DateTime endDate { get; set; } public bool isDeprecated { get; set; } } 

Агентство

 public class Agency { [Key] public int AgencyId { get; set; } public string Name { get; set; } public int PatientAddressId { get; set; } public virtual Address Address { get; set; } } 

диагностика

 public class Diagnosis { [Key] public int DiagnosisId { get; set; } public string Icd9Code { get; set; } public string Description { get; set; } public DateTime DateOfDiagnosis { get; set; } public string Onset { get; set; } public string Details { get; set; } } 

OrderApprovalStatus

 public class OrderApprovalStatus { [Key] public int OrderApprovalStatusId { get; set; } public string Status { get; set; } } 

пользователь

 public class User { [Key] public int UserId { get; set; } public string Login { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string NPI { get; set; } public string Email { get; set; } } 

ПРИМЕЧАНИЕ. АДРЕСНЫЙ КЛАСС – НОВЫЙ ДОПОЛНЕНИЕ ВО ВРЕМЯ РЕДАКТИРОВАНИЯ

Адрес

 public class Address { [Key] public int AddressId { get; set; } public string StreetAddress { get; set; } public string City { get; set; } public string State { get; set; } public string Zip { get; set; } public string Phone { get; set; } public string Title { get; set; } public string Label { get; set; } } 

Код, который выполняет сериализацию, приведен здесь:

Выписка из OrderController

  public ActionResult GetAll() { return Json(ppEFContext.Orders, JsonRequestBehavior.AllowGet); } 

благодаря

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

 public ActionResult GetAll() { return Json(ppEFContext.Orders .Include(o => o.Patient) .Include(o => o.Patient.PatientAddress) .Include(o => o.CertificationPeriod) .Include(o => o.Agency) .Include(o => o.Agency.Address) .Include(o => o.PrimaryDiagnosis) .Include(o => o.ApprovalStatus) .Include(o => o.Approver) .Include(o => o.Submitter), JsonRequestBehavior.AllowGet); } 

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

редактировать

Нет необходимости удалять virtual ключевое слово из свойств навигации (что сделало бы ленивую загрузку полностью невозможной для модели). Достаточно отключить создание прокси-сервера (что также отключает ленивую загрузку) для конкретных обстоятельств, когда прокси-серверы беспокоят, например, сериализацию:

 ppEFContext.Configuration.ProxyCreationEnabled = false; 

Это отключает создание прокси только для конкретного экземпляра контекста ppEFContext .

(Я только что видел, @WillC уже упомянул об этом здесь. Upvote для этого отредактируйте, пожалуйста, к его ответу.)

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

 using (var context = new MeContext()) { context.Configuration.ProxyCreationEnabled = false; return context.cars.Where(w => w.Brand == "Ferrari") } 

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

то есть:

 {Models.car} 

вместо

 {System.Data.Entity.DynamicProxies.car_231710A36F27E54BC6CE99BB50E0FE3B6BD4462EC‌​A19695CD1BABB79605296EB} 

Проблема в том, что вы фактически сериализуете объект прокси-объекта, созданный сущностью. К сожалению, это связано с некоторыми проблемами при использовании с сериализатором JSON. Вы можете рассмотреть возможность сопоставления своих объектов с особыми classами POCO ради совместимости с JSON.

Существует атрибут для добавления объектов Entity Framework

 [ScriptIgnore] 

Это заставляет код не выполнять Циркулярные ссылки.

Я думаю, они исправили это в последней версии.

Ознакомьтесь с документами справки в разделе « Сериализация и десериализация JSON -> Сериализация и сохранение ссылок на объекты ».

Установите этот параметр при инициализации сериализатора JSON.Net:

 PreserveReferencesHandling = PreserveReferencesHandling.Objects; 

Таким образом, пример будет таким:

 var serializerSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects }; string json = JsonConvert.SerializeObject(people, Formatting.Indented, serializerSettings); 

Я проверил, что это работает с моим первым решением для кода и круговой ссылкой в ​​свойствах навигации. Если вы посмотрите на полученный JSON, он должен иметь свойства «$ id» и «$ ref» во всем мире.

Альтернативным решением будет использование анонимных типов в результате запроса LINQ.

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

Альтернативным решением, если нужны только некоторые значения из объектов, является создание анонимного classа и его возврат, как показано ниже:

 public JsonResult AjaxFindByName(string term) { var customers = context.Customers .Where(c => c.Name.ToUpper().Contains(term.ToUpper())).Take(10) .AsEnumerable() .Select(c => new { value = c.Name, SSN = String.Format(@"{0:000\-00\-0000}", c.SSN), CustomerID = c.CustomerID }); return Json(customers, JsonRequestBehavior.AllowGet); } 

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

У вас есть несколько способов:

  • Отключайте загрузку при загрузке вашего запроса (linq или lambda) DbContext.Configuration.ProxyCreationEnabled = false;
  • Удалить ключевое слово virtual из Domainmodel
  • Отсоедините объекты (= нет загружаемых функций и без прокси)
    • Repository.Detach (EntityObject)
    • DbContext.Entry (entityObject) .EntityState = EntityState.Detached
  • Клонировать свойства
    • Вы можете использовать что-то вроде AutoMapper для клонирования объекта, не используйте интерфейс ICloneable, потому что он также клонирует ProxyProperties в объекте, так что это не сработает.
  • Если вы создаете API, попробуйте использовать проект separte с другой конфигурацией (которая не возвращает прокси)

PS. Proxies – это объект, созданный EF, когда вы загружаете его из Entity Framework. Короче: это означает, что он содержит исходные значения и обновленные значения, чтобы их можно было обновить позже. Он обрабатывает другие вещи 😉

Для тех, кто использует classы прокси EF / Linq2SQL, моим решением было просто удалить родительскую ссылку для моих дочерних объектов.

Поэтому в моей модели я выбрал отношения и изменил ссылку «Родитель» как «Внутренний», а не «Общественный».

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

Вы можете удалить ключевое слово virtual :

public virtual Patient Patient { get; set; } public virtual Patient Patient { get; set; } -> public Patient Patient { get; set; } public Patient Patient { get; set; }

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

Я смог решить эту проблему, используя описанный здесь метод:

http://mytechworld.officeacuity.com/index.php/2010/02/serializing-entity-framework-objects-into-json-using-asp-net-mvc/

  • Как реализовать TypeAdapterFactory в Gson?
  • Преобразование любого объекта в массив байтов в java
  • Исключение «Исключительная привязка к реляционной ссылке» с JSON.Net
  • Невозможно десериализовать lambda
  • C # десериализация структуры после ее получения через TCP
  • Специальная сериализация Jackson JSON для определенных полей
  • jQuery serializeArray не включает кнопку отправки, которая была нажата
  • C # JSON.NET - десериализация ответа, использующего необычную структуру данных
  • Json.NET: десериализация вложенных словарей
  • Задача не сериализуема: java.io.NotSerializableException при вызове функции закрытие только для classов не объектов
  • Сериализация OpenCV Mat_
  • Interesting Posts

    Пользовательская обработка SSL перестала работать на Android 2.2 FroYo

    Обработчики событий ASP.NET Button не срабатывают при первом щелчке, но при втором нажатии после PostBack

    SEL выполняет выбор и аргументы

    Как получить консоль устройства в Xcode6?

    Ionic2 / Angular2 – прочитать пользовательский файл конфигурации

    Снижение производительности String.intern ()

    Два компьютера с объединенными ресурсами процессора и памяти?

    Как изменить значения между двумя столбцами

    Вкладка не принимает полную ширину на планшетном устройстве

    Переключение User-Agent в Firefox 4

    Использование триггеров MySQL для регистрации всех изменений таблицы во вторичной таблице

    Обработка перенаправления HttpClient

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

    Разница между @Before, @BeforeClass, @BeforeEach и @BeforeAll

    Как добавить значок в приложение, построенное с помощью Eclipse Galileo C и MinGW?

    Давайте будем гением компьютера.