简体   繁体   English

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

[英]Override SaveChangesAsync Entity Framework 6 to log modified property values

I'm developing an ASP.NET Core project where in SaveChanges , I need to log the updated values我正在开发一个 ASP.NET 核心项目,在SaveChanges中,我需要记录更新的值

According to this I tried to override SaveChangesAsync but I get this error:根据这个我试图覆盖SaveChangesAsync但我得到这个错误:

Unable to cast object of type 'MyProject.ApplicationDbContext' to type 'System.Data.Entity.Infrastructure.IObjectContextAdapter'.无法将类型为“MyProject.ApplicationDbContext”的 object 转换为类型“System.Data.Entity.Infrastructure.IObjectContextAdapter”。

Code:代码:

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

Also I tried to compose the log string in the Action method but I get the same error.我也尝试在 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]);
    }
}

I'm using EF 6.我正在使用 EF 6。

I need to log the property name, old value and new value.我需要记录属性名称、旧值和新值。 I can't get why I'm getting that error, what am I doing wrong?我不明白为什么我会收到那个错误,我做错了什么?

what am I doing wrong?我究竟做错了什么?

Using an example from EF 4.1?使用 EF 4.1 中的示例? :) :)

You can utilize the ChangeTracker in EF 6 to accomplish what you are looking for.您可以利用 EF 6 中的 ChangeTracker 来完成您正在寻找的内容。 I would recommend setting up a separate DbContext for your logging containing just the logging table and FKs as needed:我建议为您的日志记录设置一个单独的 DbContext,根据需要仅包含日志记录表和 FK:

Within your SaveChanges/SaveChangesAsync overrides:在您的 SaveChanges/SaveChangesAsync 覆盖中:

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

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

From here you can access the original and modified property values through OriginalValues and CurrentValues respectively.从这里您可以分别通过OriginalValuesCurrentValues访问原始和修改的属性值。

** Update ** When reporting on changes the typical easy way is to use ToObject() on the OriginalValues and CurrentValues then serialize to something like Json to capture the before and after state of the object in question. ** 更新 ** 当报告更改时,典型的简单方法是在 OriginalValues 和 CurrentValues 上使用ToObject() ,然后序列化为 Json 之类的内容,以捕获问题中 ZA8CFDE6331BD49EB2AC96F966F9 的 state 之前和之后的 state。 However this will display all modified and unmodified values.但是,这将显示所有修改和未修改的值。

To iterate through the values to find actual changes is a bit more involved:遍历这些值以找到实际的变化有点复杂:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM