覆盖 SaveChangesAsync Entity Framework 6 以记录修改后的 属性 值

Override SaveChangesAsync Entity Framework 6 to log modified property values

我正在开发 ASP.NET 核心项目,其中 SaveChanges,我需要记录更新的值

根据 this 我试图覆盖 SaveChangesAsync 但我得到这个错误:

Unable to cast object of type 'MyProject.ApplicationDbContext' to type 'System.Data.Entity.Infrastructure.IObjectContextAdapter'.

代码:

public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
    ChangeTracker.DetectChanges();

    ObjectContext ctx = ((IObjectContextAdapter)this).ObjectContext;

    List<ObjectStateEntry> objectStateEntryList = ctx.ObjectStateManager
                                                     .GetObjectStateEntries((System.Data.Entity.EntityState)(EntityState.Added | EntityState.Modified | EntityState.Deleted))
                                                     .ToList();

    foreach (ObjectStateEntry entry in objectStateEntryList)
    {
        if (!entry.IsRelationship)
        {
            switch (entry.State)
            {
                case (System.Data.Entity.EntityState)EntityState.Added:
                    // write log...
                    break;

                case (System.Data.Entity.EntityState)EntityState.Deleted:
                    // write log...
                    break;

                case (System.Data.Entity.EntityState)EntityState.Modified:
                    foreach (string propertyName in entry.GetModifiedProperties())
                    {
                        DbDataRecord original = entry.OriginalValues;
                        string oldValue = original.GetValue(original.GetOrdinal(propertyName)).ToString();

                        CurrentValueRecord current = entry.CurrentValues;
                        string newValue = current.GetValue(current.GetOrdinal(propertyName)).ToString();

                        if (oldValue != newValue) // probably not necessary
                        {
                            var a = string.Format("Entry: {0} Original :{1} New: {2}",
                                                  entry.Entity.GetType().Name,
                                                  oldValue, newValue);
                        }
                    }
                    break;
           }
       }
   }

   return base.SaveChangesAsync();
}

我也尝试在 Action 方法中编写日志字符串,但我得到了同样的错误。

public async Task<IActionResult> Edit(MyModel model)
{
    ...
    // _context is ApplicationDbContext()
    var myObjectState = _context.ObjectStateManager.GetObjectStateEntry(model);
    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]);
    }
}

我正在使用 EF 6。

我需要记录 属性 名称、旧值和新值。我不明白为什么会出现该错误,我做错了什么?

what am I doing wrong?

使用 EF 4.1 中的示例? :)

您可以利用 EF 6 中的 ChangeTracker 来完成您要查找的内容。我建议为您的日志记录设置一个单独的 DbContext,仅包含日志记录 table 和需要的 FK:

在您的 SaveChanges/SaveChangesAsync 覆盖范围内:

var updatedEntities = ChangeTracker.Entries()
    .Where(x => x.State == EntityState.Modified);

var insertedEntities = ChangeTracker.Entries()
    .Where(x => x.State == EntityState.Added);

从这里您可以分别通过 OriginalValuesCurrentValues 访问原始和修改后的 属性 值。

** 更新** 报告更改时,典型的简单方法是在 OriginalValues 和 CurrentValues 上使用 ToObject(),然后序列化为 Json 之类的东西,以捕获相关对象的前后状态。然而,这将显示所有修改和未修改的值。

遍历值以查找实际更改有点复杂:

foreach(var entity in updatedEntities)
{
    foreach (var propertyName in entity.OriginalValues.PropertyNames)
    {
        if (!object.Equals(entity.OriginalValues.GetValue<object>(propertyName), 
        entity.CurrentValues.GetValue<object>(propertyName)))
        {
            var columnName = propertyName;
            var originalValue = entity.OriginalValues.GetValue<object>(propertyName)?.ToString() ?? "#null";
            var updatedValue = entity.CurrentValues.GetValue<object>(propertyName)?.ToString() ?? "#null";
            var message = $"The prop: {columnName} has been changed from {originalValue} to {updatedValue}";
        }
    }
}