获取对Entity Framework中的对象所做的所有更改

Wil*_*lem 45 c# entity-framework

有没有办法在保存所有更改之前获取对实体框架中的对象所做的所有更改.原因是我想在客户端数据库中创建一个日志表:

所以...

有没有办法在保存更改之前获取当前数据库值(旧)和新值(当前)?

如果没有,我怎么能以通用的方式实现这一点,所以我的所有View Models都可以继承?(我使用的是MVVM + M结构)

Pan*_*vos 59

您可以使用ObjectContext的ObjectStateManager,GetObjectStateEntry来获取对象的ObjectStateEntry,该对象在OriginalValuesCurrentValues属性中保存其原始值和当前值.您可以使用GetModifiedProperties方法获取已更改的属性的名称.

你可以这样写:

var myObjectState=myContext.ObjectStateManager.GetObjectStateEntry(myObject);
var modifiedProperties=myObjectState.GetModifiedProperties();
foreach(var propName in modifiedProperties)
{
    Console.WriteLine("Property {0} changed from {1} to {2}", 
         propName,
         myObjectState.OriginalValues[propName],
         myObjectState.CurrentValues[propName]);
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您正在努力获得 ObjectStateManager,则可能需要强制转换: var objectStateManager = ((IObjectContextAdapter)dbContext).ObjectContext.ObjectStateManager; (7认同)
  • 看一下这篇文章[使用EF ObjectContext审计跟踪](http://www.codeproject.com/Articles/34491/Implementing-Audit-Trail-using-Entity-Framework-Pa) (2认同)

Jür*_*ock 37

对于EF5以上,您可以在SaveChanges()方法中记录您的更改,如下所示:

    public override int SaveChanges()
    {

        var changes = from e in this.ChangeTracker.Entries()
                      where e.State != System.Data.EntityState.Unchanged
                      select e;

        foreach (var change in changes)
        {
            if (change.State == System.Data.EntityState.Added)
            {
                // Log Added
            }
            else if (change.State == System.Data.EntityState.Modified)
            {
                // Log Modified
                var item = change.Cast<IEntity>().Entity;
                var originalValues = this.Entry(item).OriginalValues;
                var currentValues = this.Entry(item).CurrentValues;

                foreach (string propertyName in originalValues.PropertyNames)
                {
                    var original = originalValues[propertyName];
                    var current = currentValues[propertyName];

                    if (!Equals(original, current))
                    {
                        // log propertyName: original --> current
                    }
                }

            }
            else if (change.State ==  System.Data.EntityState.Deleted)
            {
                // log deleted
            }
        }
        // don't forget to save
        base.SaveChanges();
    }
Run Code Online (Sandbox Code Playgroud)


swe*_*tfa 8

我使用此扩展函数提供有关要更改的实体,旧值和新值,数据类型和实体键的详细信息.

这是使用ObjectContext使用EF6.1测试的,并使用log4net进行输出.

    /// <summary>
    /// dump changes in the context to the debug log
    /// <para>Debug logging must be turned on using log4net</para>
    /// </summary>
    /// <param name="context">The context to dump the changes for</param>
    public static void DumpChanges(this ObjectContext context)
    {
        context.DetectChanges();
        // Output any added entries
        foreach (var added in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added))
        {
            Log.DebugFormat("{0}:{1} {2} {3}", added.State, added.Entity.GetType().FullName, added.Entity.ToString(), string.Join(",", added.CurrentValues.GetValue(1), added.CurrentValues.GetValue(2)));
        }
        foreach (var modified in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
        {
            // Put original field values into dictionary
            var originalValues = new Dictionary<string,int>();
            for (var i = 0; i < modified.OriginalValues.FieldCount; ++i)
            {
                originalValues.Add(modified.OriginalValues.GetName(i), i);
            }
            // Output each of the changed properties.
            foreach (var entry in modified.GetModifiedProperties())
            {
                var originalIdx = originalValues[entry];
                Log.DebugFormat("{6} = {0}.{4} [{7}][{2}] [{1}] --> [{3}]  Rel:{5}", 
                    modified.Entity.GetType(), 
                    modified.OriginalValues.GetValue(originalIdx), 
                    modified.OriginalValues.GetFieldType(originalIdx), 
                    modified.CurrentValues.GetValue(originalIdx), 
                    modified.OriginalValues.GetName(originalIdx), 
                    modified.IsRelationship, 
                    modified.State, 
                    string.Join(",", modified.EntityKey.EntityKeyValues.Select(v => string.Join(" = ", v.Key, v.Value))));
            }
        }
        // Output any deleted entries
        foreach (var deleted in context.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted))
        {
            Log.DebugFormat("{1} {0} {2}", deleted.Entity.GetType().FullName, deleted.State, string.Join(",", deleted.CurrentValues.GetValue(1), deleted.CurrentValues.GetValue(2)));
        }
    }
Run Code Online (Sandbox Code Playgroud)


mar*_*n_x 6

使用IsModified每个属性的字段,可以通过 访问该字段Context.Entry(Entity).Properties

Tuple在此示例中,修改的条目作为原始值和当前值列出,并按名称索引。使用构建审核日志所需的任何转换。

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

//...

// gets somewhere in the scope
DbContext Context;
// Some entity that has been modified, but not saved and is being tracked by Context
object Entity;

//...

Dictionary<string, System.Tuple<object, object>> modified = 
    Context.Entry(Entity)
        .Properties.Where(p => p.IsModified)
        .ToDictionary(p => p.Metadata.Name, 
                      p => new System.Tuple<object,object>(p.OriginalValue, p.CurrentValue));
//...
Run Code Online (Sandbox Code Playgroud)

使用 Entity Framework Core 3.1。尝试使用EF 6.4,但可能不起作用。