Реализация отслеживания изменений объекта в N-уровневом приложении WCF MVC.

Большинство примеров, которые я видел в Интернете, показывают отслеживание изменений объекта в контексте WinForms / WPF. Или, если он находится в сети, используются связанные объекты, поэтому изменения, внесенные в каждый объект, можно отслеживать.

В моем сценарии объекты отключаются, как только они покидают уровень данных (отображаются в бизнес-объекты в WCF и отображаются в DTO в приложении MVC)

Когда пользователи вносят изменения в объект в MVC (например, изменяют свойство 1 поля), как мне отправить это изменение из представления вплоть до БД?

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

Я могу придумать несколько способов сделать это

1) Реализуйте флаг IsDirty для каждого свойства для всех моделей на уровне MVC (или в javascript?). Распространите эту информацию обратно на уровень сервиса и, наконец, на уровень данных.

2) Было бы здорово иметь этот механизм отслеживания изменений на уровне сервиса, но как я могу затем отслеживать «исходные» значения после того, как измененные значения были переданы обратно из MVC?

3) Триггеры базы данных? Но я не знаю, с чего начать. Это вообще возможно?

Существуют ли какие-либо известные реализации отслеживания изменений объектов для n-уровневого решения mvc-wcf?

Пример таблицы аудита:

Audit table

Id              Object         Property         OldValue                NewValue
--------------------------------------------------------------------------------------
1               Customer       Name             Bob                     Joe
2               Customer       Age              21                      22

person Null Reference    schedule 22.07.2013    source источник
comment
+1 Когда пользователи вносят изменения в объект в MVC (например, изменяют свойство 1 поля), как мне отправить это изменение из представления, вплоть до базы данных? Вы можете объяснить это ?   -  person Imad Alazani    schedule 22.07.2013
comment
Отредактировано для большей ясности   -  person Null Reference    schedule 22.07.2013
comment
Просто выполните сопоставление с классами ORM (Entity Framework?) И вызовите SaveChanges(). Какой у Вас вопрос?   -  person Federico Berasategui    schedule 22.07.2013
comment
@ The8thBit: Это означает, что во время выполнения, когда значение конкретного объекта изменяется ..., вы хотите отслеживать его, сохраняя в базе данных?   -  person Imad Alazani    schedule 22.07.2013
comment
Я хочу сохранить значения до и после в таблице аудита объекта   -  person Null Reference    schedule 22.07.2013
comment
@ The8thBit: Можете ли вы сказать, что нужно за этой реализацией?   -  person Imad Alazani    schedule 22.07.2013
comment
@PKKG Это чувствительная система. Все пользователи сайта должны нести ответственность за изменения, которые они внесли в любую запись / объект на сайте.   -  person Null Reference    schedule 22.07.2013


Ответы (2)


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

Другими словами, после того, как он «покидает» базу данных, блокируется ли она исключительно для пользователя или могут ли другие пользователи или процессы тем временем обновлять ее?

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

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

Если, с другой стороны, никакие другие пользователи или процессы не могут изменять данные, тогда у вас есть несколько различных вариантов, которые различаются по сложности, хранению данных и влиянию на существующие структуры данных.

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

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

Вы также можете глубоко клонировать объект и передавать его по слоям. Затем, когда пришло время определить, что изменилось, вы снова можете использовать отражение. Однако, в зависимости от размера ваших бизнес-объектов, этот подход может значительно снизить производительность, поскольку полная копия должна быть перемещена по сети и сохранена вместе с исходной записью.

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

person competent_tech    schedule 22.07.2013
comment
Нет, ничего не закрывается. Другие пользователи могут редактировать те же данные. - person Null Reference; 22.07.2013
comment
Хорошо, тогда я определенно рекомендую извлекать исходную запись в начале той же транзакции, которую вы используете для обновления записи. Мы широко используем это в системе, в которой одновременно работают тысячи пользователей, которые отправляют данные через веб-клиенты, мобильные устройства, электронную почту, приложения форм выигрыша и т. Д. Все данные от всех клиентов проходят через единую точку доступа на уровне приложения, и это где мы проводим аудит, как описано. - person competent_tech; 22.07.2013
comment
Итак, вы говорите, я должен сделать что-то вроде этого: например, пользователь хочет отредактировать данные клиента. 1) получить данные клиента из уровня обслуживания (WCF). 2) изменяет 1 свойство (например, имя) 3) при сохранении (отправляет данные обратно на уровень обслуживания), снова получить запись и выполнить сравнение? - person Null Reference; 22.07.2013
comment
Да, именно так. Проблема в том, что даже если этот пользователь изменил 1 свойство, если 4 других пользователя изменили разные свойства, и вы перезаписали все эти свойства тем, на которое пользователь смотрит на своем экране, технически последний пользователь обновил ВСЕ эти свойства, не только тот, который они изменили в пользовательском интерфейсе. - person competent_tech; 22.07.2013

Ваш вопрос состоит из двух частей:

  1. Как это сделать в MVC:

Обычный способ: вы отправляете изменения обратно на сервер, контроллер обрабатывает их и т.д. и т.п. Для вашего сценария использования лучше, чтобы изменения были закодированы как отдельные операции изменения, а не как измененный объект, когда вам нужно было использовать отражение, чтобы узнать, какие изменения внес пользователь.

  1. Как это сделать в базе данных: это, вероятно, ваш предполагаемый вопрос:

Прежде всего, держитесь подальше от ORM-фреймворков, жизнь слишком сложна.

На последнем этапе операции сохранения у вас должна быть следующая информация:

  • Объекты и поля, которые необходимо изменить, и их новые значения.

Вам необходимо отслеживать следующую информацию:

  • Какое последнее изменение объекта, который вы собираетесь изменить в базе данных.

Его можно получить из таблицы аудита, и его необходимо сохранить в сеансе (или в объекте, подобном сеансу).

Затем в транзакции нужно сделать следующее:

  • Получите последнее изменение объекта (ов) из базы данных.
  • Если объекты изменились, отмените операцию и сообщите пользователю о столкновении.
  • Если нет, получить текущие значения изменяемых полей.
  • Сохраните новые значения.
  • Обновите таблицу аудита.

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

person Eli Algranti    schedule 22.07.2013
comment
Как мне отслеживать изменения объекта, который я собираюсь изменить в базе данных? Предлагает ли это полностью реализовать флаг isDirty во ViewModel уровня MVC и полностью передать его обратно на уровень данных? - person Null Reference; 22.07.2013
comment
1. Нет, у вас уже есть аудит, если вам нужно изменить идентификатор клиента = 12, просто запишите идентификатор последнего изменения этого объекта в трассировке аудита. 2. Для вашего варианта использования вам необходимо иметь способ определять, какие поля были изменены. Это может быть грязный флаг, но гораздо эффективнее было бы иметь журнал изменений: объект, который инкапсулирует изменения, например Клиент: 10, Поле: Имя, Значение: Боб. Это напрямую повлияет на изменения в базе данных. - person Eli Algranti; 22.07.2013
comment
Вопрос. Вы говорите: Во-первых, держитесь подальше от ORM-фреймворков, жизнь слишком сложна. - Как вы сохраняете изменения? Сам писать sql? Или использовать DataTables? - person Maarten; 22.07.2013
comment
Лично я предпочитаю использовать микроорганизм, такой как Dapper, и использовать хранимые процедуры для хранения фактического SQL. Таким образом, по-прежнему существует интерфейс между БД и приложением, и специалисты по БД могут оптимизировать запросы в своей собственной среде. - person Eli Algranti; 23.07.2013