История снимков с платформой Entity

Я искал некоторые крючки для аудита с Entity Framework. Многие из них показывают сравнение старых/новых значений. Это отлично подходит для аудита, но я ищу объекты моментальных снимков.

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

Если я использую SQL Server, какой тип я должен использовать для сериализованного объекта в настоящее время (XML, blob и т.д.)? Имеет ли смысл делать это?

Ответы

Ответ 1

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

То, что вы хотите сделать, очень распространено. Рассмотрим механизм вики. Вики должны иметь ревизию подсказки, которую все видят, а также обратно ревизии каждого документа. Вики также должны иметь возможность отображать обратную ревизию точно так же, как отображается ревизия подсказки. Поэтому для обоих из них должен использоваться один и тот же формат хранения.

Я бы предложил, чтобы вы разрешили все типы объектов. Когда вы редактируете тип сущности, вы редактируете ревизию подсказки и сохраняете обратную ревизию, содержащую предыдущие значения. (Причина, по которой вы редактируете ревизию подсказки вместо того, чтобы вставлять новый совет, состоит в том, что другие объекты, которые в настоящее время не реализованы в ObjectContext, могут содержать ссылки на подсказку, которые вы хотели бы сохранить в качестве ссылок на кончик, а не ссылки на назад ревизия.)

При необходимости вы можете разбить свои таблицы SQL Server так, чтобы обратные ревизии были сохранены в другой группе файлов. Это позволит вам отдельно резервировать ревизии и обратно ревизии.

Ответ 2

В проекте, который мы недавно создали, мы использовали метод SaveChanges в классе DbContext. Это дало нам доступ к экземпляру класса ChangeTracker. Вызов ChangeTracker.Entries() дает вам доступ к списку DbEntityEntry. DbEntityEntry имеет следующие интересные свойства и методы:

  • State - это объект, созданный, измененный или удаляемый
  • Entity - копия объекта как таковой
  • CurrentValues - перечисление отредактированного значения
  • OriginalValues - перечисление исходных значений

Мы создали набор POCOs для наборов изменений и изменений, которые мы могли бы получить через EF. Это позволило нашим пользователям просматривать изменения на уровне поля вместе с датами и ответственными пользователями.

Ответ 3

Сначала вам нужно добавить набор свойств в свои таблицы:

  • Версия - время последней модификации (также может быть автоинкрементным счетчиком вместо времени).
  • LastModifiedBy - ссылка на пользователя, внесшего последнюю модификацию (если вы ее сохранили).

Затем у вас есть несколько вариантов хранения истории версий. Вы можете

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

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

Как вы заполняете свои таблицы истории? Через триггеры обновления и удаления.

  • В триггере обновления для вашего объекта - скопируйте все предыдущие значения в таблицу истории. Для каждого внешнего ключа - также копируйте текущую версию ссылочного объекта.
  • В триггере удаления - в основном делают то же самое.

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

Как вы просматриваете свою историю? Просто используйте таблицу истории, поскольку она имеет все те же свойства, что и основная таблица, - не должно быть проблемой. Но - при расширении внешних ключей - убедитесь, что ссылочная версия Version такая же, как и в вашей таблице истории. Если это не так - вам нужно перейти в таблицу "История" этого ссылочного объекта и получить значения там. Таким образом, у вас всегда будет снимок того, как объект выглядел в момент THAT, включая все ссылки.

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

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