#c# #wpf #wcf #entity-framework #self-tracking-entities
#c# #wpf #wcf #entity-framework #самослеживающиеся объекты
Вопрос:
Это общий вопрос архитектуры, надеюсь, для людей, которые уже используют EF в конечных приложениях.
У нас есть типичное N-уровневое приложение:
- Клиент WPF
- Службы WCF
- EF STE DTO
- Уровень данных EF
Приложение загружает все известные бизнес-типы во время загрузки (одновременно с входом пользователя в систему), затем загружает очень большой «Рабочий пакет» по запросу, этот пакет составляет около 4-8 мг и состоит из более чем 1000 бизнес-объектов. Когда мы завершаем загрузку этого «пакета», мы затем связываем все с ранее загруженными бизнес-типами и т.д…
В итоге у нас в памяти около 2-5 Тыс. бизнес-объектов, на которые все правильно ссылаются, поэтому мы можем использовать LINQ на стороне клиента и злоупотреблять им. Мы также выполняем некоторую сложную математику для всех этих объектов на стороне клиента, поэтому нам действительно нужен большой график.
Проблема возникает, когда мы хотим сохранить изменения в базе данных. С таким большим графом объектов мы вряд ли захотим снова отправлять все по сети.
Наш текущий подход, который мне не нравится, учитывая сложность шаблонов T4 на данный момент, заключается в том, чтобы отсоединять и присоединять все при обновлении. По сути, мы хотим обновить данный объект, отделить его от остальной части графика, отправить по сети, обновить его на стороне WCF, а затем снова подключить его на стороне клиента. Основная проблема заключается в том, что когда вы хотите обновить связанные объекты, допустим, вы добавляете что-то, что имеет ссылку на что-то, что также добавлено, затем другую ссылку на что-то измененное и т.д. Это заставляет много клиентского кода следить за тем, чтобы мы ничего не нарушали.
Все это делается с помощью сгенерированного кода, поэтому мы говорим о 200-800 строках кода T4 на шаблон.
То, что я рассматриваю прямо сейчас, — это способ настроить сериализацию и десериализацию STE, чтобы я мог контролировать, что отправляется по сети, а что нет, и иметь возможность обновлять пакеты вместо одного STE. Проверяя ссылки, посмотрите, остались ли эти ссылки неизменными или нет; если нет, не сериализуйте, если да, сериализуйте и обновляйте все, просто прикрепляя это к контексту на стороне WCF.
После некоторого изучения я нашел 2 решения для этого метода.
Один из них заключается в написании пользовательского DataContractSerializer.
Второй способ заключается в изменении шаблона STE, созданного EF, и поиграйте с атрибутом KnownTypeAttribute, вместо того чтобы генерировать его для каждого ссылочного типа, пусть он ссылается на метод, который проверяет объект и помечает только те ссылки сериализации, которые не являются неизменными.
- Кто-нибудь когда-нибудь сталкивался с этой проблемой раньше?
- Какие решения вы использовали?
- С какими проблемами вы столкнулись в дальнейшем?
- Насколько легко было поддерживать созданные шаблоны?
Ответ №1:
Я не знаю всего дизайна приложения, но если вы обычно загружаете рабочий пакет в службу, а затем отправляете его клиенту, чтобы поиграть с ним, похоже, что уровень сервиса почему-то не нужен, и вы можете напрямую загружать данные из базы данных (и вы получите намного лучшую производительность). В зависимости от сложности вычислений вы также можете выполнить некоторые вычисления непосредственно в базе данных, и вы снова получите намного лучшую производительность.
Ваш подход к сохранению только части графика является злоупотреблением концепцией STE. STE работает следующим образом — вы загружаете график, изменяете график и сохраняете тот же график. Если вы хотите иметь большой набор данных для чтения и сохранять только небольшие фрагменты, вероятно, лучше загрузить набор данных для чтения, и как только вы решите обновить фрагмент, снова загрузите только фрагмент, измените его и отправьте обратно.
Вмешательство во внутреннее поведение STEs, по-моему, лучший способ потерять некоторые изменения в некоторых неожиданных сценариях.
Кстати. это как-то похоже на сценарий синхронизации локальной базы данных с глобальной — я никогда этого не делал, но это довольно распространено в смарт-клиентах.
Комментарии:
1. На самом деле нет, потому что это используется через Интернет, и о предоставлении доступа к SQL Server напрямую не может быть и речи, правила инфраструктуры, DMZ и т.д. Не позволяют вам этого делать. Не говоря уже о том, что некоторые люди, которые будут использовать это приложение, находятся в управляемых интернетах, и обычно порт 80 открыт для HTTP, в то время как порт TCP 1433 для SQL Server много раз закрыт.
2. У нас не может быть только фрагментов графа объектов, поскольку ко всему графу применяется некоторая сложная математика, которая многое в нем обновляет. Конечным результатом этого является то, что видит и воспринимает пользователь. Мы также не получаем всю базу данных, поскольку она содержит несколько таких графиков больших объектов, мы загружаем только по одному за раз, в соответствии с запросом пользователя. Бизнес заключается в управлении приложениями для европейского финансирования исследований и разработок, поэтому нам нужно загрузить весь «проект», выполнить всю математику того, что нужно сократить, каковы фактические затраты, инвестиции, что приемлемо или нет, что на самом деле будет оплачено фондом и т.д.
3. Хорошо, теперь это имеет смысл при использовании WCF, но все же идея с синхронизацией локальной базы данных с глобальной БД через WCF (это должно быть возможно с MS Sync framework) звучит как решение с гораздо меньшим количеством проблем. Я не думаю, что STE — это то, что вам нужно, потому что их назначение другое.
4. Что ж, я изучал синхронизацию, когда разрабатывал первую версию архитектуры, и что заставило меня отказаться от нее, так это то, что вам приходилось хранить локальную копию ваших данных, либо внедряя локальное хранилище, либо развертывая SQL Server Express (что отключило бы развертывание click once), а также STE предоставляет вам некоторую хорошую функциональность привязки WPF «из коробки», многие взаимосвязи реализованы в виде TrackableCollection, Которая оборачивается вокруг ObservableCollection и т.д. Прямо сейчас это работает хорошо, оно находится в производстве, и никакие данные не теряются. Проблема в том, что шаблоны выглядят некрасиво, я думаю, что существует лучший способ
5. Sync Framework также поддерживает .NET compact, и если у вас есть локальное хранилище, вы также можете использовать EF напрямую с привязкой данных. Шаблоны выглядят некрасиво, их сложно разрабатывать, сложно поддерживать, сложно отлаживать и т.д. И все еще никто не говорит, что ваше изменение будет работать, потому что одно дело — модифицировать граф объектов и другое — поддерживать его в соответствии с внутренним отслеживанием STE.