Реализация журнала аудита / История изменений с помощью MVC и Entity Framework

Я создаю журнал изменений / журнал аудита для своего MVC-приложения, которое использует Entity Framework.

Таким образом, специально в методе редактирования public ActionResult Edit(ViewModel vm) мы обнаруживаем объект, который мы пытаемся обновить, а затем используйте TryUpdateModel(object) для переноса значений из формы на объект, который мы пытаемся обновить.

Я хочу зарегистрировать изменение, когда изменится какое-либо поле этого объекта. Поэтому в основном мне нужна копия объекта, прежде чем он будет отредактирован, а затем сравните его после того, как TryUpdateModel(object) выполнил свою работу. т.е.

 [HttpPost] public ActionResult Edit(ViewModel vm) { //Need to take the copy here var object = EntityFramework.Object.Single(x=>x.ID = vm.ID); if (ModelState.IsValid) { //Form the un edited view model var uneditedVM = BuildViewModel(vm.ID); //this line seems to confuse the EntityFramework (BuildViewModel() is used to build the model when originally displaying the form) //Compare with old view model WriteChanges(uneditedVM, vm); ... TryUpdateModel(object); } ... } 

Но проблема в том, что код извлекает «unedited vm», это вызывает некоторые неожиданные изменения в EntityFramework – так что TryUpdateModel(object); генерирует UpdateException .

Поэтому возникает вопрос – в этой ситуации – как создать копию object вне EntityFramework для сравнения для истории изменений / аудита, чтобы он не влиял и не изменял EntityFramework вообще

edit: Не хотите использовать триггеры. Необходимо зарегистрировать имя пользователя, которое это сделало.

edit1: Использование EFv4, не слишком уверенно, как перейти к переопределению SaveChanges() но это может быть вариант


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

 public partial class Entities { public override int SaveChanges(SaveOptions options) { DetectChanges(); var modifiedEntities = ObjectStateManager.GetObjectStateEntries(EntityState.Modified); foreach (var entry in modifiedEntities) { var modifiedProps = ObjectStateManager.GetObjectStateEntry(entry).GetModifiedProperties(); //This line throws exception The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object of type 'System.Data.Objects.EntityEntry'. var currentValues = ObjectStateManager.GetObjectStateEntry(entry).CurrentValues; foreach (var propName in modifiedProps) { var newValue = currentValues[propName]; //log changes } } //return base.SaveChanges(); return base.SaveChanges(options); } } 

    ЕСЛИ вы используете EF 4, вы можете подписаться на событие SavingChanges .

    Поскольку Entities – это частичный class, вы можете добавить дополнительную функциональность в отдельный файл. Итак, создайте новый файл с именем Entities и там реализуйте частичный метод OnContextCreated чтобы подключить событие

     public partial class Entities { partial void OnContextCreated() { SavingChanges += OnSavingChanges; } void OnSavingChanges(object sender, EventArgs e) { var modifiedEntities = ObjectStateManager.GetObjectStateEntries(EntityState.Modified); foreach (var entry in modifiedEntities) { var modifiedProps = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).GetModifiedProperties(); var currentValues = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).CurrentValues; foreach (var propName in modifiedProps) { var newValue = currentValues[propName]; //log changes } } } } 

    Если вы используете EF 4.1, вы можете пройти эту статью, чтобы извлечь изменения

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

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

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

    В кодебере есть статья с высоким рейтингом: Реализация аудита с использованием Entity Framework . Кажется, он делает то, что вы хотите. Я начал использовать это решение в проекте. Я сначала написал триггеры в T-SQL в базе данных, но было слишком сложно поддерживать их с изменениями в объектной модели, которые происходят все время.

    Давайте будем гением компьютера.