#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» должен быть загружен…
Это невозможно при использовании отложенной загрузки. Как только объект будет сериализован, сериализатор получит доступ к каждому отдельному свойству. Доступ к каждому свойству навигации вызовет отложенную загрузку, и сериализатор продолжит работу с загруженными свойствами => он всегда будет сериализовывать полный граф объекта. В вашем сценарии это может означать:
- Сериализатор запустится с
Person
, которые имеют свойство навигации кPlace
- Отложенная загрузка загрузит
Place
, и сериализатор выполнит сериализацию. - Если у
Place
есть свойство навигации для всехPersons
, отложенная загрузка инициирует и загружает всех пользователей, ссылающихся наPlace
! - Сериализатор начнет сериализацию каждого загруженного файла
Person
— еслиIsReference
установлено значениеfalse
, вы получите исключение с циклами в графе объектов. В противном случае это создаст огромное сообщение.
Это очень простое объяснение того, что произойдет, если вы попытаетесь сериализовать объект при использовании отложенной загрузки. Если у ваших объектов есть другие свойства навигации, для них произойдет тот же эффект. В худшем случае вы можете легко создать операцию, которая попытается извлечь и сериализовать все данные из базы данных. Это, скорее всего, приведет к таймауту.
Есть еще одна проблема с отложенной загрузкой. Сериализация выполняется за пределами области действия. Итак, если вы закроете / утилизируете ObjectContext
в операции, вы получите исключение, когда объект запускает отложенную загрузку.
Не используйте отложенную загрузку при отображении объектов в WCF или не используйте DTO для управления тем, какие данные должны быть переданы из операции.
Комментарии:
1. все это правда. Если вы не хотите, чтобы отложенная загрузка полностью загружала все ваши экземпляры, тогда вы могли бы заменить
Place
экземпляр наPlaceProxy
, который реализует тот же интерфейс, но имеет только инициализированные свойства soem, а остальные не являются операционными. Не решает вопрос OPs о том, почему циклы все еще происходят (предполагая, что это действительно ее проблема). Тем не менее, вы должны предпочтительно возвращать DTO из службы. Затем проблема исчезает.2. Спасибо за ваш ответ. Я думал, что понимаю проблему, но теперь это намного более ясно. Я думаю, что создам свою собственную модель (почти такую же, как моя модель EF) только с некоторыми свойствами для каждого объекта и загружу ее перед возвратом. Вы имеете в виду это с DTO?? Или я должен создавать разные классы для каждого случая, который я найду?? Спасибо!!
3. Да, я имею в виду это под моделью. Создание разных классов для каждого случая также возможно, но это требует много работы. Обычно используется в больших проектах или при оптимизации объема передаваемых данных.
4. Хорошо, большое спасибо. Я хотел избежать этого, потому что у меня огромный объем данных, и я думал, что Microsoft предоставит какое-либо решение 😉
Ответ №3:
Возможно, вы захотите преобразовать ваше дерево объектов в другие, плоские объекты и вернуть их вместо этого.
Комментарии:
1. Я думал об этом варианте, но у меня огромная модель данных, и я думал, что смогу избежать большого объема работы ;-). Спасибо за ваш ответ, я отмечу его как правильный, если я окончательно решу его с помощью этого.