Using MVC and Entity Framework to Implement Audit Log / Change History

asp.net-mvc audit c# entity-framework

Question

A Change History / Audit Log is being added to my MVC program, which uses Entity Framework.

in particular, the edit techniquepublic ActionResult Edit(ViewModel vm) after locating the item we are attempting to edit, we utilizeTryUpdateModel(object) to translate the form's data onto the object we're attempting to change.

When any field in that object changes, I want to record the change. Therefore, in order to compare the item after editing, I need a duplicate of it before editing.TryUpdateModel(object) has finished the job. i.e.

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

However, there is an issue with the method retrieving the "unedited vm," since this results in some unanticipated modifications to the EntityFramework.TryUpdateModel(object); hurls anUpdateException .

What should I do in this case to make a duplicate of theobject To compare for change/audit history outside of EntityFramework, such that it has no impact on or alters EntityFramework at all

Want to avoid using triggers. The username that did it must be recorded.

edit1: When using EFv4, I'm unsure of how to handle overrides.SaveChanges() but it may be a choice.


For such a straightforward demand, this technique appears to be ineffective! I eventually managed to correctly override it, however now that function throws an exception:

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);
    }
}
1
32
7/29/2011 4:40:46 AM

Accepted Answer

You may subscribe to the IF you are using EF 4SavingChanges event.

Since Entities is a partial class to which you may add further features in a different file. Create a new file with the nameEntities then put the imperfect approach into practice.OnContextCreated to connect the occasion

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
            }
        }
    }
}

If you are running EF 4.1, you may extract modifications by going through this piece.

24
7/29/2011 5:50:23 AM

Popular Answer

See the Entity Framework logging library I created for this, FrameLog. It is open-source and may be used commercially.

I am aware that you would want to see a code sample demonstrating how to do this, however the code becomes fairly lengthy in order to appropriately cover all the logging scenarios, such as relationship modifications and many-to-many updates. If the library is not a suitable match for your requirements, you are free to modify the code.

All scalar and navigation property changes may be tracked by FrameLog, and you can also choose to just track changes to a specific subset of those properties.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow