Реализация журнала аудита / истории изменений с помощью MVC и Entity Framework - PullRequest
31 голосов
/ 29 июля 2011

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

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

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

[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);
    }
    ...
}

Но проблема в том, что когда код получает «неотредактированный 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);
    }
}

Ответы [ 3 ]

23 голосов
/ 29 июля 2011

Если вы используете 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, вы можете просмотреть эту статью извлечь изменения

15 голосов
/ 23 апреля 2013

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

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

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

1 голос
/ 09 июля 2012

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

...