覆盖 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);
从这里您可以分别通过 OriginalValues
和 CurrentValues
访问原始和修改后的 属性 值。
** 更新**
报告更改时,典型的简单方法是在 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}";
}
}
}
我正在开发 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);
从这里您可以分别通过 OriginalValues
和 CurrentValues
访问原始和修改后的 属性 值。
** 更新**
报告更改时,典型的简单方法是在 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}";
}
}
}