Отслеживание изменений в графе сложных объектов

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

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

Теоретическая проблема в моем случае определяется в многоуровневой архитектуре (не обязательно n-уровневой в данный момент) следующим образом:

  • Слой репозиториев, использующий ORM для иметь дело с постоянством (инструмент ORM на данный момент не имеет значения, но, скорее всего, это будет Entity Framework 4.0 или NHibernate).
  • Набор чистых классов (постоянный ignorant = POCO, который эквивалентен POJO в мире Java), представляющих объекты домена. Хранилища сохраняют эти классы и возвращают их как результаты запросов.
  • Набор услуг домена, работающих с объектами домена.
  • Фасадный слой, определяющий шлюз к бизнес-логике. Внутренне он использует репозитории, доменные службы и доменные объекты. Объекты домена не отображаются - каждый метод фасада использует набор специализированных объектов передачи данных для параметра и возвращаемого значения. Каждый метод фасада отвечает за преобразование сущности домена в DTO и наоборот.
  • Современное веб-приложение, которое использует фасадный слой и DTO - я называю это автономное приложение. Как правило, дизайн может измениться в будущем, так что слой Фасад будет обернут слоем веб-службы, а веб-приложение будет использовать этот сервис => переход на трехуровневый (веб, бизнес-логика, база данных).

Теперь предположим, что одним из объектов домена является Order, который имеет детали (строки) Order и связанные Order. Когда клиент запрашивает Заказ для редактирования, он может изменить Заказ, добавить, удалить или изменить любую деталь Заказа и добавить или удалить связанные Заказы. Все эти модификации делаются на данных в веб-браузере - Javascript и AJAX. Таким образом, все изменения отправляются в одном кадре, когда клиент нажимает кнопку сохранения. Вопрос в том, как справиться с этими изменениями? Хранилище и инструмент ORM должны знать, какие объекты и отношения были изменены, вставлены или удалены. Я закончил с двумя «лучшими» решениями:

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

  2. Не отслеживать изменения в DTO вообще. При получении измененных данных в фасадном слое создайте измененную сущность и загрузите фактическое состояние из хранилища (как правило, дополнительный запрос к базе данных - это вопрос, который меня не очень устраивает) - объедините эти две сущности и автоматически отследите изменения по прокси сущности, предоставленному инструментом ORM (Entity Framework 4.0 и NHibernate позволяют это). Особая осторожность необходима для обработки параллелизма, поскольку фактическое состояние не обязательно должно быть начальным состоянием.

Что ты думаешь об этом? Что вы порекомендуете?

Я знаю, что некоторых из этих проблем можно избежать, используя кеширование на некоторых прикладных уровнях, но это то, что я сейчас не хочу использовать.

Мой интерес к этой теме идет еще дальше. Например, предположим, что приложение использует трехуровневую архитектуру, а клиент (веб-приложение) не будет записан в классах .NET = DTO, которые нельзя использовать повторно. Отслеживание изменений в DTO будет намного сложнее, потому что от другой команды разработчиков потребуется надлежащая реализация механизма отслеживания в своих инструментах разработки.

Я считаю, что эти проблемы необходимо решать во многих приложениях, поделитесь своим опытом.

10
задан Ladislav Mrnka 16 August 2010 в 13:31
поделиться

1 ответ

Все дело в ответственности.

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

Итак, у нас есть несколько уровней в системе - каждый отвечает за свою задачу: доступ к данным, пользовательский интерфейс, бизнес-логика и т. Д. Когда мы проектируем систему таким образом, мы (среди прочего) пытаемся внести изменения в будущем. Легко, сделав каждый компонент ответственным за одну задачу, чтобы он мог сосредоточиться на этой одной задаче и выполнять ее хорошо. Это также упрощает модификацию системы по прошествии времени и необходимости изменений.

Подобные мысли следует иметь в виду при рассмотрении DTO - «как отслеживать изменения?» Например. Вот как я подхожу к этому: BL отвечает за управление правилами и логикой; с учетом того, что сеть не имеет состояния (в которой я выполняю большую часть своей работы), я просто не отслеживаю состояние объекта и не ищу явных изменений. Если пользователь передает данные обратно (для сохранения / обновления), я передам все обратно, не заботясь о том, что было изменено.

С одной стороны, это может показаться неэффективным, но, поскольку объемы данных невелики, это не проблема; С другой стороны, меньше «движущихся частей», меньше может выйти из строя, так как процесс намного проще.

Как передать данные обратно? -

  • Я использую DTO (или, возможно, POCO было бы точнее); когда я обмениваюсь данными между BL и DAL (через интерфейсы / DI ), данные передаются как DTO (или их совокупность). В частности, я использую структуру для одного экземпляра и коллекцию этих структур для нескольких.

  • DTO определены в общем классе, который имеет очень мало зависимостей.

  • Я намеренно пытаюсь ограничить количество DTO, созданных для определенного объекта (например, «Порядок»), но в то же время я создам новые, если для этого есть веская причина. Обычно у меня есть «толстый» DTO, который содержит большую часть / все данные, доступные для этого объекта, я также, вероятно, буду иметь гораздо более компактный, предназначенный для использования в коллекциях (для списков и т. Д.). В обоих случаях эти DTO являются чистым средством для возврата информации для "чтения". Вы должны помнить об ответственности - когда BL запрашивает данные, он обычно не пытается записать данные обратно в одно и то же время; поэтому тот факт, что DTO доступен только для чтения, больше связан с чистым интерфейсом и архитектурой, чем с бизнес-правилом.

  • Я всегда определяю отдельные DTO для вставки и обновления - даже если они имеют одни и те же поля. Таким образом, худшее, что может случиться, - это дублирование некоторого альтернативного кода, в отличие от наличия зависимостей и множества вариантов повторного использования, которые нужно распутать.

Наконец - не путайте, как работает DAL с тем, как работает пользовательский интерфейс; Позвольте ORM делать свое дело, просто потому, что они хранят данные определенным образом, не означает, что это единственный способ.

Самым важным является определение значимых интерфейсов между вашими уровнями.

Управление тем, что изменилось, - это работа BL; пусть UI работает так, как лучше для ваших пользователей, и пусть BL выясняет, как он хочет с этим справиться, а DAL (через ваш красивый чистый интерфейс с DI ) просто делает то, что ему говорят.

3
ответ дан 4 December 2019 в 03:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: