与MVC和放大器实现审计日志/更改历史记录;实体框架 [英] Implementing Audit Log / Change History with MVC & Entity Framework

查看:212
本文介绍了与MVC和放大器实现审计日志/更改历史记录;实体框架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立了更改历史记录/审计日志到正在使用的实体框架我的MVC应用程序。

所以,特别是在编辑方法公众的ActionResult编辑(视图模型VM),我们发现我们正在努力更新,然后使用该对象 TryUpdateModel (对象)来转上,我们正在努力更新对象从表单中的值。

我要记录的变化时的对象更改的任何字段。所以基本上我需要的是对象的副本是编辑,然后在 TryUpdateModel(对象)后,比较之前已完成其工作。即。

  [HttpPost]
公众的ActionResult编辑(视图模型VM)
{
    //这里需要采取副本
    VAR对象= EntityFramework.Object.Single(X => x.ID = vm.ID);    如果(ModelState.IsValid)
    {
        //形成未编辑视图模型
        VAR uneditedVM = BuildViewModel(vm.ID); //这一行似乎混淆的EntityFramework(BuildViewModel()用于构建模型时最初显示的形式)
        //旧视图模型比较
        WriteChanges(uneditedVM,VM);
        ...
        TryUpdateModel(对象);
    }
    ...
}

但问题是当code检索未经编辑虚拟机,这是造成中的EntityFramework一些意想不到的变化 - 这样 TryUpdateModel(对象); 抛出一个 UpdateException

所以,问题是 - 在这种情况下 - 我怎么创建对象的副本的EntityFramework之外,比较变更/审计历史,所以它不会影响或改变
在的EntityFramework所有

编辑:不要使用触发器。需要登录谁做的用户名。

EDIT1:使用EFv4,也不太清楚如何去覆盖的SaveChanges(),但它可能是一种选择


这条路线似乎无处可去,这样一个简单的要求!我终于得到它正确地覆盖,但现在我得到与code异常:

 公共部分类实体
{
    公共覆盖INT的SaveChanges(SaveOptions选项)
    {
        DetectChanges();
        VAR modifiedEntities = ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
        的foreach(在modifiedEntities VAR进入)
        {
            VAR modifiedProps = ObjectStateManager.GetObjectStateEntry(项).GetModifiedProperties(); //此行抛出异常的ObjectStateManager不包含ObjectStateEntry一起类型的对象System.Data.Objects.EntityEntry的参考。
            VAR currentValues​​ = ObjectStateManager.GetObjectStateEntry(入门).CurrentValues​​;
            的foreach(在modifiedProps VAR作为propName)
            {
                VAR为newValue = currentValues​​ [作为propName]
                //记录更改
            }
        }        //返回base.SaveChanges();
        返回base.SaveChanges(选件);
    }
}


解决方案

如果您使用的是EF 4,您可以订阅 SavingChanges 事件。

由于实体是一个局部类你可以在一个单独的文件添加额外的功能。因此,创建一个名为实体一个新的文件,并没有实施 OnContextCreated 部分的方法挂钩事件

 公共部分类实体
{
    部分无效OnContextCreated()
    {
        SavingChanges + = OnSavingChanges;
    }    无效OnSavingChanges(对象发件人,EventArgs的发送)
    {        VAR modifiedEntities = ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
        的foreach(在modifiedEntities VAR进入)
        {
            变种modifiedProps = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).GetModifiedProperties();
            VAR currentValues​​ = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).CurrentValues​​;
            的foreach(在modifiedProps VAR作为propName)
            {
                VAR为newValue = currentValues​​ [作为propName]
                //记录更改
            }
        }
    }
}

如果您使用的是EF 4.1你可以通过<一个href=\"http://blogs.msdn.com/b/adonet/archive/2011/01/30/using-dbcontext-in-ef-feature-ctp5-part-5-working-with-property-values.aspx\">this文章提取变化

I am building in a Change History / Audit Log to my MVC app which is using the Entity Framework.

So specifically in the edit method public ActionResult Edit(ViewModel vm), we find the object we are trying to update, and then use TryUpdateModel(object) to transpose the values from the form on to the object that we are trying to update.

I want to log a change when any field of that object changes. So basically what I need is a copy of the object before it is edited and then compare it after the TryUpdateModel(object) has done its work. 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);
    }
    ...
}

But the problem is when the code retrieves the "unedited vm", this is causing some unexpected changes in the EntityFramework - so that TryUpdateModel(object); throws an UpdateException.

So the question is - in this situation - how do I create a copy of the object outside of EntityFramework to compare for change/audit history, so that it does not affect or change the EntityFramework at all

edit: Do not want to use triggers. Need to log the username who did it.

edit1: Using EFv4, not too sure how to go about overriding SaveChanges() but it may be an option


This route seems to be going nowhere, for such a simple requirement! I finally got it to override properly, but now I get an exception with that code:

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

解决方案

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

Since Entities is a partial class you can add additional functionality in a separate file. So create a new file named Entities and there implement the partial method OnContextCreated to hook up the event

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 using EF 4.1 you can go through this article to extract changes

这篇关于与MVC和放大器实现审计日志/更改历史记录;实体框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆