Audit.NET 连接的对象保存问题



我正在使用 Audit.NET 和EntityFramework扩展,当我只跟踪1个实体时,一切都运行良好。

现在我也在跟踪连接到第一个实体的另一个实体,当我尝试保存它时,审计保存函数会抛出反射错误

System.Reflection.TargetException:"对象与目标类型不匹配。

我的类的结构是这样的:

public class FirstClass{
public int ID{get;set;}
//Some props here
public SecondClass SecondClass{get;set}
}
public class SecondClass{
public int ID{get;set;}
public int FirstClassId{get;set;}
public MySpecialClass JustForData{get;set;}
//Some other props here
}

然后,我只是将我的 Audit 类建模为完全相同,但添加了审核字段

public class AuditClass{
public Guid AuditId{get;set;}
public string AuditMessage{get;set;}
}
public class FirstClassAudit : AuditClass{
public int ID{get;set;}
//Some props here
//No SecondClass prop here
}
public class SecondClassAudit: AuditClass{
public int ID{get;set;}
public int FirstClassId{get;set;}
public MySpecialClass JustForData{get;set;}
//Some other props here
}

然后在FirstClassAudit中省略了对二等的引用

我的两个类都在 DbContext 中,每个审计类都映射到一个单独的表。 我在 AuditTypeExplicitMapper 下添加了两个类的映射,我调试了它,没有问题。 但是我仍然在保存更改功能上收到错误

当我在保存时将第二类引用保留为 null 时,这似乎不会发生

编辑:更多信息

Audit.NET 配置:

Audit.Core.Configuration.Setup()
.UseEntityFramework(
ef => ef
.AuditTypeExplicitMapper(m => m
.Map<FirstClass, FirstClassAudit>((frst, auditFrst) =>
{
//Map the tag fields in here
auditFrst.Tag = frst.Installation.Tag;
//Some more props here
})
.Map<SecondClass, SecondClassAudit>()
.AuditEntityAction((ev, ent, auditEntity) =>
{
((AuditClass)auditEntity).AuditMessage = ent.Action;
}))
);

在 DbContext 中保存函数:

public override int SaveChanges()
{
return Helper.SaveChanges(auditContext, () => base.SaveChanges());
}

编辑 2:堆栈跟踪

at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target( at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture( at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture( at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index( at Audit.EntityFramework.Providers.EntityFrameworkDataProvider.CreateAuditEntity(Type definingType, Type auditType, EventEntry entry( at Audit.EntityFramework.Providers.EntityFrameworkDataProvider.InsertEvent(AuditEvent auditEvent( at Audit.Core.AuditScope.SaveEvent(Boolean forceInsert( at Audit.Core.AuditScope.Save(( at Audit.EntityFramework.DbContextHelper.SaveScope(IAuditDbContext context, AuditScope scope, EntityFrameworkEvent event( at Audit.EntityFramework.DbContextHelper.SaveChanges(IAuditDbContext context, Func'1 baseSaveChanges( at MyDbContext.SaveChanges(( in [MyLocalPath]\MyDbContext.cs:line 132 at FirstClassRepository.UpdateFirstClass(Int32 id, FirstClassDto first( in [MyLocalPath]\FirstClassRepository.cs:line 209 at FirstClassManager.UpdateFirstClass(Int32 id, FirstClassDto dto( in [MyLocalPath]\FirstClassManager.cs:line 244 at FirstClassController.<>c__DisplayClass20_0.b__0(( in [MyLocalPath]\FirstClassController.cs:line 249

编辑: 在摆弄了更多之后,我得到了错误,通过将"MySpecialClass"添加到映射中来说明它是什么类型

System.ArgumentException:"类型为'MySpecialClass'的对象不能转换为类型'AuditMySpecialClass'。

这个类是我的数据上下文中的拥有类型,这可能与它有关,也许不是。

现在,错误似乎在到达可以在映射中添加的用户定义操作之前被抛出,可能是 Audit.NET 尝试在用户定义的操作之前映射这些内容?

使用最新版本的 Audit.EntityFramework (15.0.2(,您现在可以仅忽略某些审核类型的属性匹配,如下所示:

Audit.Core.Configuration.Setup()
.UseEntityFramework(ef => ef
.AuditTypeExplicitMapper(m => m
.Map<FirstClass, FirstClassAudit>((frst, auditFrst) =>
{
auditFrst.Tag = frst.Installation.Tag;
})
.Map<SecondClass, SecondClassAudit>()
.AuditEntityAction((ev, ent, auditEntity) =>
{
((AuditClass)auditEntity).AuditMessage = ent.Action;
}))
.IgnoreMatchedProperties(t => t == typeof(FirstClassAudit)) // <-- Ignore prop. matching for FirstClassAudit
);

所以,我找到了一个解决方案。这不是我想要的 100%,但它有效。

问题出在我的"MySpecialClass"对象上,因为它们是 EFCore 中拥有的类型,它们生成了自己的单独事件,这混淆了 Audit.NET

所以我在"MySpecialClass"声明上方添加了[AuditIgnore],并将IgnoreMatchedProperties添加到配置中

[AuditIgnore]
public class MySpecialClass
{
public Unit? UnitOfMeasure { get; set; }
public float? Value { get; set; }
}
Audit.Core.Configuration.Setup()
.UseEntityFramework(
ef => ef
.AuditTypeExplicitMapper(m => m
.Map<FirstClass, FirstClassAudit>((frst, auditFrst) =>
{
MapMatchedProperties(frst, auditFrst);
//Map the tag fields in here
auditFrst.Tag = frst.Installation.Tag;
//Some more props here
})
.Map<SecondClass, SecondClassAudit>((scnd, auditScnd)=>
{
MapMatchedProperties(scnd, auditScnd);
})
.AuditEntityAction((ev, ent, auditEntity) =>
{
((AuditClass)auditEntity).AuditMessage = ent.Action;
}))
.IgnoreMatchedProperties()
);

我还添加了我自己的映射函数"MapMatchedProperties"来正确映射每个字段,但"MySpecialClass"的特殊例外

private static void MapMatchedProperties(object source, object destination)
{
var sourceType = source.GetType();
var destinationType = destination.GetType();
var sourceFields = sourceType.GetProperties();
var destinationFields = destinationType.GetProperties();
foreach (var field in sourceFields)
{
var destinationField = destinationFields.FirstOrDefault(f => f.Name.Equals(field.Name));
if (destinationField != null && (destinationField.PropertyType == field.PropertyType))
{
//Normal field
var sourceValue = field.GetValue(source);
destinationField.SetValue(destination, sourceValue);
} else if(destinationField != null && (destinationField.PropertyType == typeof(AuditMySpecialClass) && field.PropertyType== typeof(MySpecialClass)))
{
//MySpecialClass field
var destinationMeasure = new AuditMySpecialClass();
var sourceValue = (MySpecialClass)field.GetValue(source);
if (sourceValue != null || sourceValue.IsEmpty())
{
destinationMeasure.UnitOfMeasure = sourceValue.UnitOfMeasure;
destinationMeasure.Value = sourceValue.Value;
}
destinationField.SetValue(destination, destinationMeasure);
}
}
}

最新更新