Подтвердить что ты не робот

Реализация журнала аудита/История изменений с помощью 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);
    }
}
4b9b3361

Ответ 1

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

Так как Entities - это частичный класс, вы можете добавить дополнительные функции в отдельный файл. Поэтому создайте новый файл с именем 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, вы можете пройти эту статью, чтобы извлечь изменения

Ответ 2

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

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

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

Ответ 3

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