Ссылка на цикл сериализации с ошибкой WCF

#c# #silverlight #wcf #entity-framework

#c# #silverlight #wcf #entity-framework

Вопрос:

Я пытаюсь вернуть списки объектов, которые имеют ссылки на другие объекты и наоборот.

Я хочу, чтобы отложенная загрузка получала только «дочерние элементы первого уровня», я имею в виду, если у меня есть объект «Person» со свойством «Place», я хочу, чтобы были загружены данные о месте, но не каждый объект в объекте «Place» должен быть загружен … потому что это привело бы к циклической ссылке…

Я читал, что я мог бы сделать это, используя [DataContract(IsReference = true)] для каждого объекта.

Я установил для каждого объекта в модели (автоматически сгенерированного EF) это оформление, но оно по-прежнему не выполняется при попытке отправить его обратно вызывающей службе.

Я что-то упускаю? Заранее спасибо.

Ответ №1:

Я [DataContract(IsReference=true)] успешно использовал для решения проблемы циклической зависимости в прошлом. По общему признанию, они не были объектами, сгенерированными EF, но я не уверен, насколько это должно иметь значение.

В чем именно заключается ошибка?

Это из-за того, что график становится слишком большим?

Может ли быть так, что ваши объекты — это не одни и те же экземпляры, а разные экземпляры концептуально одного и того же типа?

Итак, когда ваш TypeA-instance1 сериализуется и у него есть ссылка на TypeB-instance1, которая имеет ссылку на TypeA-instance1, два фактических объекта TypeA-instance1 не сравниваются равными, поэтому сериализатор не пытается повторно использовать ссылки?

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

Комментарии:

1. Хммм, звучит интересно. Мой сервис просто вылетает, когда пытается вернуть значение, а не циклические ссылки или что-то еще, что я могу понять… Я взгляну на это. Спасибо за ваш ответ.

2. вы включили ведение журнала? Это может подсказать вам, в чем проблема, или, по крайней мере, позволит увидеть возникающее исключение.

3. После долгого поиска в Google по этой проблеме я должен сказать, что атрибут [DataContract (IsReference = true)] в моих классах DTO сработал для меня!

Ответ №2:

Я имею в виду, если у меня есть объект «Person» со свойством «Place», я хочу, чтобы были загружены данные о месте, но не каждый объект в объекте «Place» должен быть загружен…

Это невозможно при использовании отложенной загрузки. Как только объект будет сериализован, сериализатор получит доступ к каждому отдельному свойству. Доступ к каждому свойству навигации вызовет отложенную загрузку, и сериализатор продолжит работу с загруженными свойствами => он всегда будет сериализовывать полный граф объекта. В вашем сценарии это может означать:

  1. Сериализатор запустится с Person , которые имеют свойство навигации к Place
  2. Отложенная загрузка загрузит Place , и сериализатор выполнит сериализацию.
  3. Если у Place есть свойство навигации для всех Persons , отложенная загрузка инициирует и загружает всех пользователей, ссылающихся на Place !
  4. Сериализатор начнет сериализацию каждого загруженного файла Person — если IsReference установлено значение false , вы получите исключение с циклами в графе объектов. В противном случае это создаст огромное сообщение.

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

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

Не используйте отложенную загрузку при отображении объектов в WCF или не используйте DTO для управления тем, какие данные должны быть переданы из операции.

Комментарии:

1. все это правда. Если вы не хотите, чтобы отложенная загрузка полностью загружала все ваши экземпляры, тогда вы могли бы заменить Place экземпляр на PlaceProxy , который реализует тот же интерфейс, но имеет только инициализированные свойства soem, а остальные не являются операционными. Не решает вопрос OPs о том, почему циклы все еще происходят (предполагая, что это действительно ее проблема). Тем не менее, вы должны предпочтительно возвращать DTO из службы. Затем проблема исчезает.

2. Спасибо за ваш ответ. Я думал, что понимаю проблему, но теперь это намного более ясно. Я думаю, что создам свою собственную модель (почти такую же, как моя модель EF) только с некоторыми свойствами для каждого объекта и загружу ее перед возвратом. Вы имеете в виду это с DTO?? Или я должен создавать разные классы для каждого случая, который я найду?? Спасибо!!

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

4. Хорошо, большое спасибо. Я хотел избежать этого, потому что у меня огромный объем данных, и я думал, что Microsoft предоставит какое-либо решение 😉

Ответ №3:

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

Комментарии:

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