Я работал с WCF RIA Services и Silverlight и добился определенного успеха в предоставлении сервиса, который обслуживает данные, взятые из модели данных объекта ADO.NET, смоделированной из существующей базы данных SQL Server 2008 Express.База данных определяет множество связей между таблицами, которые я надеюсь использовать на стороне клиента для привязки данных.
Все шло гладко, пока я не попытался выполнить следующий метод обслуживания:
public IQueryable<Timeline> GetHighlights() {
var self = from x in Database.Timelines
where User.Id == x.UserId || User.Id == x.SenderId
select x;
var friends = from x in Database.FriendItems
where User.Id == x.UserId
from y in Database.Timelines
where x.FriendId == y.UserId || x.FriendId == y.SenderId
select y;
return self.Concat(friends).OrderByDescending(s => s.Id);
}
Примечание: «Пользователь» - это внутреннее свойство класса, которое выбирает текущего пользователя, прошедшего проверку подлинности, а база данных просто оборачивает свойство ObjectContext (для простоты).
Объект «Временная шкала» содержит 2 свойства навигации: «Пользователь» и«Отправитель», связанный с сущностью «SilverfishUser».Когда я перебираю результаты запроса «self», я вижу, что ранее упомянутые свойства были заполнены текущим пользователем (что правильно).Однако, когда я повторяю результаты запроса «друзей», оба свойства равны нулю (перед сериализацией для клиента).
Я попытался установить:
this.ContextOptions.LazyLoadingEnabled = false;
//and
this.ContextOptions.ProxyCreationEnabled = false;
И у меня естьтакже пытался загружать ссылки с помощью метода запросов «Включить» (с отложенной загрузкой, оба включены и отключены), но безрезультатно.
Единственный способ, которым я успешно заполнил свойства «Пользователь» и «Отправитель» сущности временной шкалы, -следующее утверждение:
friends.ForEach(s => {
if (!s.UserReference.IsLoaded) s.UserReference.Load();
if (!s.SenderReference.IsLoaded) s.SenderReference.Load();
});
Насколько я понимаю, операция «Загрузка» приводит к выполнению отдельного запроса к базе данных.Как видите, это представляет потенциально неэффективную ситуацию, когда у пользователя много друзей с большим количеством сообщений на временной шкале.Точную ситуацию я пытаюсь избежать, отключив ленивую загрузку.Я хочу вернуть клиенту полностью загруженную сущность, с которой можно связать минимальное количество запросов.
Я уже преодолел одну проблему, когда относительные свойства не были сериализованы для клиента путем применения [Включить] атрибут в определения свойств метаданных, сгенерированные мастером службы домена.Эта проблема кажется немного более сложной, решения, которые я попробовал, были широко изложены другими и должны решить мою проблему в теории, но они этого не делают.Опять же, единственный способ успешно заполнить сущность - это явно загрузить ссылки, используя сгенерированное свойство EntityReference <>, созданное для связанного свойства.
Любая помощь, опыт или информация по этой проблемес благодарностью.
[EDIT] Обновление некоторых моих исследований, когда я выполняю запрос, подобный следующему:
var friends = Database.FriendItems
.Include("Friend.Timeline")
.Where(s => User.Id == s.UserId);
и доступ к свойствам навигации ("friends.First ().Friend.Timeline.First (). User ") значение не равно нулю.Только когда я выбираю временные шкалы в новую коллекцию, добавляя что-то вроде:
.SelectMany(s => s.Friend.Timeline);
, свойства навигации больше не имеют никакого значения.Теперь это только предположение, но я могу только предположить, что оно проецирует значения свойств в новый экземпляр объекта, поэтому он не перезаполняет эти свойства в попытке избежать циклических ссылок?Во всяком случае, это чертовски трудно решить.Надеюсь, есть кто-то, кто знает об этом больше, чем я.