У меня есть клиент WCF, который передает объекты самообследования в приложение WPF, созданное с помощью MVVM. Само приложение имеет динамический интерфейс. Пользователи могут выбирать, какие объекты они хотят видеть в своей рабочей области, в зависимости от их роли или выполняемой задачи.
Мои сущности с самообследованием имеют довольно много навигационных свойств, и многие из них не нужны. Поскольку некоторые из этих объектов могут быть довольно большими, я хотел бы загружать эти свойства только по запросу.
Мое приложение выглядит так:
[WCF] <---> [ClientSide Repository] <---> [ViewModel] <---> [View]
Мои модели являются объектами с самостоятельным отслеживанием. Клиентский репозиторий подключает метод LazyLoad (при необходимости) перед возвратом модели в ViewModel, который ее запросил. Все вызовы службы WCF являются асинхронными, что означает, что методы LazyLoad также являются асинхронными.
Реальная реализация LazyLoad доставляет мне некоторые проблемы. Вот варианты, которые я придумал.
РЕДАКТИРОВАТЬ - я удалил примеры кода, чтобы их было легче читать и понимать. Смотрите предыдущую версию вопроса, если хотите ее увидеть
Вариант A
Асинхронно LazyLoad свойства модели с сервера WCF в Getter
Хорошо: Загрузка данных по запросу чрезвычайно проста. Привязка в XAML загружает данные, поэтому, если элемент управления находится на экране, данные загружаются асинхронно и уведомляют пользовательский интерфейс, когда он там есть. Если нет, ничего не загружается. Например, <ItemsControl ItemsSource="{Binding CurrentConsumer.ConsumerDocuments}" />
загрузит данные, однако, если раздела «Документы» интерфейса нет, ничего не загружается.
Плохо: Невозможно использовать это свойство в любом другом коде до его инициализации, поскольку оно возвратит пустой список. Например, следующий вызов всегда вернет false, если документы не были загружены.
public bool HasDocuments
{
get { return ConsumerDocuments.Count > 0; }
}
ВАРИАНТ B
Вручную сделать вызов для загрузки данных при необходимости
Хорошо: Простота реализации - просто добавьте LoadConsumerDocumentsSync()
и LoadConsumerDocumentsAsync()
методы
Плохо: Не забудьте загрузить данные, прежде чем пытаться получить к ним доступ, в том числе, когда они используются в привязках. Это может показаться простым, но может быстро выйти из-под контроля. Например, каждый ConsumerDocument имеет UserCreated и UserLastModified. Существует DataTemplate, который определяет UserModel с всплывающей подсказкой, отображающей дополнительные пользовательские данные, такие как добавочный номер, электронная почта, команды, роли и т. Д. Поэтому в моей ViewModel, которая отображает документы, мне нужно было бы вызвать LoadDocuments
, затем просмотреть их и вызвать LoadConsumerModified
и LoadConsumerCreated
. Это может продолжаться тоже ... после этого мне придется LoadUserGroups
и LoadUserSupervisor
. Также существует риск возникновения циклических циклов, когда что-то вроде User
имеет свойство Groups[]
, а Group
имеет свойство Users[]
ОПЦИЯ C
Мой любимый вариант на данный момент ... создать два способа доступа к собственности. Одна синхронизация и одна асинхронная. Привязки будут сделаны к свойству Async, и любой код будет использовать свойство Sync.
Хорошо: Данные загружаются асинхронно по мере необходимости - именно то, что я хочу. Не так уж много дополнительного кодирования, так как все, что мне нужно сделать, это изменить шаблон T4 для генерации этих дополнительных свойств / методов.
Плохо: Наличие двух способов доступа к одним и тем же данным кажется неэффективным и запутанным. Вам нужно помнить, когда вы должны использовать Consumer.ConsumerDocumentsAsync
вместо Consumer.ConsumerDocumentsSync
. Существует также вероятность того, что вызов службы WCF будет выполнен несколько раз, и для этого требуется дополнительное свойство IsLoaded для каждого навигационного свойства, например IsConsumerDocumentsLoaded.
ОПЦИЯ D
Пропустите асинхронную загрузку и просто загрузите все синхронно в установщики.
Хорошо: Очень просто, дополнительная работа не требуется
Плохо: Блокирует интерфейс при загрузке данных. Не хочу этого.
ОПЦИЯ E
Пусть кто-нибудь на SO скажет мне, что есть другой способ сделать это, и укажет мне примеры кода:)
Другие заметки
Некоторые из NavigationProperties будут загружены на сервер WCF перед возвратом объекта клиенту, однако другие слишком дороги, чтобы сделать это с помощью.
За исключением ручного вызова событий Load в варианте C, все это может быть выполнено с помощью шаблона T4, поэтому для меня очень мало кода. Все, что мне нужно сделать, это подключить событие LazyLoad в клиентском репозитории и указать его на правильные вызовы службы.