2009-09-21 5 views
15

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

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

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

+0

Я добавлю щедрость, чтобы получить более подробный ответ: –

+1

@AnynameDonotcare для каждой таблицы, в которой вы хотите сохранить историю: 1) добавить столбец версии (может быть время, может увеличивать счетчик). 2) добавить другую таблицу со всеми теми же свойствами, что и основная таблица (но лучше расширить внешние ключи). 3) Перед запуском обновления, если столбец версии изменился - скопируйте старые значения в эту таблицу версий. 4) Прибыль. – Evk

+0

@ Evk: Я буду так благодарен, если бы вы могли добавить подробный ответ простым примером (с использованием 'EF') можно было бы использовать в качестве базы для корпоративного приложения (относительно действия удаления и связей mm) –

ответ

11

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

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

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

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

+0

Очень хорошая идея ... – RailRhoad

+0

'Я бы предложил вам разрешить все типы ваших сущностей. 'Не могли бы вы подробнее рассказать о том, что вы подразумеваете под этим? –

3

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

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

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

3

Прежде всего, необходимо добавить набор свойств для таблиц:

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

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

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

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

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

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

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

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

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

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

+0

Почему вы предпочитаете первый подход по сравнению со вторым, хотя он включает в себя более избыточные данные и требует больше хранилища db? Триггеры вызывают проблемы с производительностью в дополнение к тому, что я хочу обрабатывать все эти операции с помощью «EF». Не могли бы вы представить простой пример (две таблицы). –

+0

Я слышу первый раз, что «вызывает проблемы с производительностью». Триггеры сами по себе не могут вызвать их, только если вы делаете какую-то тяжелую логику внутри. В общем, вы можете сделать это в EF точно так же - только в обработчике обновления скопируйте все текущие значения сначала в таблицу истории (не уверен, какой пример я могу здесь предоставить), я полагаю, вы знаете, как копировать значения из одного объекта в другой). Я предпочитаю первый подход, потому что он более простой и понятный, плюс позволяет легко восстановить любую предыдущую версию. В дополнение к этому - он позволяет _search_ в истории (что может быть сложнее сделать, если вы сериализуете). – Evk

+0

, если я хочу обработать логику триггера через «EF», если она будет в транзакции? –

Смежные вопросы