C# 审核实体框架删除了保留以前值的条目
我已经为一个问题挣扎了一段时间,这个问题包括在保存数据库实体时对其进行常规审计。我有一个使用EF 6的项目,我需要创建一个“非侵入性”方法,在实体被添加、修改或删除时对其进行审计。我必须在不干扰正常流的情况下存储插入实体、修改实体或删除实体的JSON。该项目有一个数据库优先实现 我的解决方案很简单,添加一个任何实体的部分类,其余的程序员想要审计实现IAudit的实体,它基本上是一个空接口,以从实现它的实体获取所有更改C# 审核实体框架删除了保留以前值的条目,c#,entity-framework,audit,C#,Entity Framework,Audit,我已经为一个问题挣扎了一段时间,这个问题包括在保存数据库实体时对其进行常规审计。我有一个使用EF 6的项目,我需要创建一个“非侵入性”方法,在实体被添加、修改或删除时对其进行审计。我必须在不干扰正常流的情况下存储插入实体、修改实体或删除实体的JSON。该项目有一个数据库优先实现 我的解决方案很简单,添加一个任何实体的部分类,其余的程序员想要审计实现IAudit的实体,它基本上是一个空接口,以从实现它的实体获取所有更改 public interface IAudit {} 我有一个货币实体,只需
public interface IAudit {}
我有一个货币实体,只需实现它而无需任何其他代码(我可以在将来做其他事情,但我不需要它)
我重写SaveChanges方法以查找要审核的实体
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
// This linq looks for new entities that were marked for audit
CreateAuditLog(System.Data.Entity.EntityState.Added);
CreateAuditLog(System.Data.Entity.EntityState.Modified);
CreateAuditLog(System.Data.Entity.EntityState.Deleted);
return base.SaveChanges();
}
该解决方案调用CreateAuditLog的3倍,因为在不久的将来,我需要实现一个配置来审核用户决定的任何内容,可能来自用户激活/停用的数据库配置
一切正常,我能够在指定状态下保存实体:
private void CreateAuditLog(System.Data.Entity.EntityState state)
{
var auditedEntities = ChangeTracker.Entries<IAudit>()
.Where(p => p.State == state)
.Select(p => p.Entity);
... some code that do something else
foreach (var auditedEntity in auditedEntities)
{
... some information I required to add
strJSON = JsonConvert.SerializeObject(auditedEntity, new EFNavigationPropertyConverter());
... some code to save audit information
}
}
private void CreateAuditLog(System.Data.Entity.EntityState)
{
var auditedEntities=ChangeTracker.Entries()
.Where(p=>p.State==State)
.选择(p=>p.Entity);
…一些做其他事情的代码
foreach(var auditedEntity in auditedEntity)
{
…我需要补充一些信息
strJSON=JsonConvert.SerializeObject(auditedEntity,新的EFNavigationPropertyConverter());
…保存审核信息的一些代码
}
}
问题是我在删除状态下丢失了所有值,我只得到ID,属性中除了ID之外没有任何信息,并且没有任何可能以任何方式提取它。我在StackOverflow和其他网站上寻找了每一个解决方案,没有任何东西可以恢复原始信息。
我如何才能让以前删除的值以与存储添加和修改的实体相同的方式存储它们?我花了几天时间才弄清楚。可能解决方案有点复杂,但我尝试了几个不太复杂的选项,但效果不佳 首先,由于我只是以一种不同的方式审核Delete,所以我将Deleted状态与Added和Modified状态分开,这两种状态在没有任何更改的情况下都能正常工作。删除状态是一种特殊情况,我就是这样对待它的 首先,我需要从数据库中获取原始值。在“已删除”状态下,它们已消失,不可能从实体中恢复它们。可以使用以下代码获取它们:
var databaseValues = this.Entry(auditedEntity).GetDatabaseValues();
结果只是DB属性值(DbPropertyValues)的集合。如果我可以获得原始值,我将从删除的实体中设置原始值:
dbEntityEntry.OriginalValues.SetValues(databaseValues);
strJSON = JsonConvert.SerializeObject(auditDeletedEntity, new EFNavigationPropertyConverter());
此行只填充实体原始值,根本不修改当前值。这样做很有用,因为需要一些代码来检查每个属性并自己设置,这是一个有趣的快捷方式。
现在,问题是我没有要序列化的实体,所以我需要一个新的实体,在我的例子中,我通过反射创建它,因为我不知道类型(我接收实现IAudit的实体)
这是我稍后将序列化以存储审核的实体
现在,复杂的部分,我需要获取实体属性,并通过实体中设置的原始值的反射来填充它们:
foreach (var propertyInfo in type.GetProperties())
{
if (!propertyInfo.PropertyType.IsArray && !propertyInfo.PropertyType.IsGenericType)
{
var propertyValue = originalValues.GetValue<object>(propertyInfo.Name);
auditDeletedEntity.GetType().InvokeMember(propertyInfo.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, auditDeletedEntity, new[] { propertyValue });
}
}
代码如下所示:
string strJSON = string.Empty;
if (state == System.Data.Entity.EntityState.Deleted)
{
var databaseValues = this.Entry(auditedEntity).GetDatabaseValues();
// Get original values from the database (the only option, in the delete method they're lost)
DbEntityEntry dbEntityEntry = this.Entry(auditedEntity);
if (databaseValues != null)
{
dbEntityEntry.OriginalValues.SetValues(databaseValues);
var originalValues = this.Entry(auditedEntity).OriginalValues;
Type type = auditedEntity.GetType();
var auditDeletedEntity = Activator.CreateInstance(type);
// Get properties by reflection
foreach (var propertyInfo in type.GetProperties())
{
if (!propertyInfo.PropertyType.IsArray && !propertyInfo.PropertyType.IsGenericType)
{
var propertyValue = originalValues.GetValue<object>(propertyInfo.Name);
auditDeletedEntity.GetType().InvokeMember(propertyInfo.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, auditDeletedEntity, new[] { propertyValue });
}
}
strJSON = JsonConvert.SerializeObject(auditDeletedEntity, new EFNavigationPropertyConverter());
}
}
else
{
strJSON = JsonConvert.SerializeObject(auditedEntity, new EFNavigationPropertyConverter());
}
string strJSON=string.Empty;
if(state==System.Data.Entity.EntityState.Deleted)
{
var databaseValues=this.Entry(auditedEntity).GetDatabaseValues();
//从数据库中获取原始值(唯一选项,在delete方法中,这些值丢失)
DbEntityEntry DbEntityEntry=此.Entry(auditedEntity);
if(数据库值!=null)
{
dbEntityEntry.OriginalValues.SetValues(数据库值);
var originalValues=this.Entry(auditedEntity).originalValues;
Type Type=auditedEntity.GetType();
var auditDeletedEntity=Activator.CreateInstance(类型);
//通过反射获取属性
foreach(type.GetProperties()中的var propertyInfo)
{
如果(!propertyInfo.PropertyType.IsArray&&!propertyInfo.PropertyType.IsGenericType)
{
var propertyValue=originalValues.GetValue(propertyInfo.Name);
AuditDeleteIdentity.GetType().InvokeMember(propertyInfo.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder,AuditDeleteIdentity,新[]{propertyValue});
}
}
strJSON=JsonConvert.SerializeObject(AuditDeleteIdentity,新的EFNavigationPropertyConverter());
}
}
其他的
{
strJSON=JsonConvert.SerializeObject(auditedEntity,新的EFNavigationPropertyConverter());
}
也许有更好的方法,但我认真地花了大量时间寻找选择,我找不到更好的方法。
非常感谢您的任何建议或优化。我花了几天时间才弄明白。可能解决方案有点复杂,但我尝试了几个不太复杂的选项,但效果不佳 首先,由于我只是以一种不同的方式审核Delete,所以我将Deleted状态与Added和Modified状态分开,这两种状态在没有任何更改的情况下都能正常工作。删除状态是一种特殊情况,我就是这样对待它的 首先,我需要从数据库中获取原始值。在“已删除”状态下,它们已消失,不可能从实体中恢复它们。可以使用以下代码获取它们:
var databaseValues = this.Entry(auditedEntity).GetDatabaseValues();
结果只是DB属性值(DbPropertyValues)的集合。如果我能得到原始值,我就从删除中设置原始值
string strJSON = string.Empty;
if (state == System.Data.Entity.EntityState.Deleted)
{
var databaseValues = this.Entry(auditedEntity).GetDatabaseValues();
// Get original values from the database (the only option, in the delete method they're lost)
DbEntityEntry dbEntityEntry = this.Entry(auditedEntity);
if (databaseValues != null)
{
dbEntityEntry.OriginalValues.SetValues(databaseValues);
var originalValues = this.Entry(auditedEntity).OriginalValues;
Type type = auditedEntity.GetType();
var auditDeletedEntity = Activator.CreateInstance(type);
// Get properties by reflection
foreach (var propertyInfo in type.GetProperties())
{
if (!propertyInfo.PropertyType.IsArray && !propertyInfo.PropertyType.IsGenericType)
{
var propertyValue = originalValues.GetValue<object>(propertyInfo.Name);
auditDeletedEntity.GetType().InvokeMember(propertyInfo.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, auditDeletedEntity, new[] { propertyValue });
}
}
strJSON = JsonConvert.SerializeObject(auditDeletedEntity, new EFNavigationPropertyConverter());
}
}
else
{
strJSON = JsonConvert.SerializeObject(auditedEntity, new EFNavigationPropertyConverter());
}