找出两个相同类型的实体之间的差异

Lan*_*usT 15 asp.net-mvc entity-framework linq-to-sql

我正在开发一个mvc3网络应用程序.当用户更新某些内容时,我想将旧数据与用户输入的新数据进行比较,并且对于每个不同的字段,将这些数据添加到日志中以创建活动日志.

现在这是我的保存动作:

[HttpPost]
public RedirectToRouteResult SaveSingleEdit(CompLang newcomplang)
{
    var oldCompLang = _db.CompLangs.First(x => x.Id == newcomplang.Id);

    _db.CompLangs.Attach(oldCompLang);
    newcomplang.LastUpdate = DateTime.Today;
    _db.CompLangs.ApplyCurrentValues(newcomplang);
    _db.SaveChanges();

    var comp = _db.CompLangs.First(x => x.Id == newcomplang.Id);

    return RedirectToAction("ViewSingleEdit", comp);
}
Run Code Online (Sandbox Code Playgroud)

我发现我可以用它来遍历我的oldCompLang属性:

var oldpropertyInfos = oldCompLang.GetType().GetProperties();
Run Code Online (Sandbox Code Playgroud)

但这并没有真正帮助,因为它只显示属性(Id,Name,Status ...)而不是这些属性的值(1,Hello,Ready ...).

我可以走得那么艰难:

if (oldCompLang.Status != newcomplang.Status)
{
    // Add to my activity log table something for this scenario
}
Run Code Online (Sandbox Code Playgroud)

但我真的不想为对象的所有属性做这件事.

我不确定迭代两个对象以查找不匹配的最佳方法是什么(例如,用户更改了名称或状态......)并根据我可以存储在另一个表中的差异构建列表.

Bro*_*ass 25

它并没有那么糟糕,您可以使用反射"手动"比较属性并编写扩展方法以供重用 - 您可以将此作为起点:

public static class MyExtensions
{
    public static IEnumerable<string> EnumeratePropertyDifferences<T>(this T obj1, T obj2)
    {
        PropertyInfo[] properties = typeof(T).GetProperties();
        List<string> changes = new List<string>();

        foreach (PropertyInfo pi in properties)
        {
            object value1 = typeof(T).GetProperty(pi.Name).GetValue(obj1, null);
            object value2 = typeof(T).GetProperty(pi.Name).GetValue(obj2, null);

            if (value1 != value2 && (value1 == null || !value1.Equals(value2)))
            {
                changes.Add(string.Format("Property {0} changed from {1} to {2}", pi.Name, value1, value2));
            }
        }
        return changes;
    }
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ell 9

如果您使用的是EntityFramework,则可以直接从ObjectContext获取更改

获取状态更改条目:

  var modifiedEntries= this.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
Run Code Online (Sandbox Code Playgroud)

获取保存的属性名称以及原始值和更改值:

  for (int i = 0; i < stateChangeEntry.CurrentValues.FieldCount - 1; i++)
            {
                var fieldName = stateChangeEntry.OriginalValues.GetName(i);

                if (fieldName != changedPropertyName)
                    continue;

                var originalValue = stateChangeEntry.OriginalValues.GetValue(i).ToString();
                var changedValue = stateChangeEntry.CurrentValues.GetValue(i).ToString();
            }
Run Code Online (Sandbox Code Playgroud)

这比@ BrokenGlass的答案更好,因为这将深入到对象图中任何已更改的状态,并将为您提供相关集合的已更改属性.它也更好,因为它反映了ObjectContext最终将保存到数据库的所有内容.使用已接受的解决方案,您可能会获得在通过对象上下文断开连接的情况下实际上不会保留的属性更改.

使用EF 4.0,您还可以覆盖SaveChanges()方法,并在与最终实体保存相同的事务中包装任何审计或活动,这意味着如果没有更改实体,审计跟踪将不存在,反之亦然.这保证了准确的日志.如果你不能保证审计准确性比它几乎无用.