[英]Audit.NET connected object save issue
我将 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
}
然后我只是将我的审计类建模为完全相同但添加了审计字段
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 中省略了对 SecondClass 的引用
我的两个类都在 DbContext 中,审计类每个都映射到一个单独的表。 我在 AuditTypeExplicitMapper 下添加了这两个类的映射,我调试通过没有问题。 但是我仍然在 SaveChanges 函数上遇到错误
当我保存时将 SecondClass 引用保留为 null 时,这似乎不会发生
编辑:更多信息
审计.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:堆栈跟踪
在 System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target) 在 System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 在 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 definitionType, 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范围,EntityFrameworkEvent 事件)在 Audit.EntityFramework.DbContextHelper.SaveChanges(IAuditDbContext context, Func`1 baseSaveChanges) 在 MyDbContex t.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) [MyLocalPath]\\FirstClassManager.cs:第 244 行在 FirstClassController.<>c__DisplayClass20_0.b__0() 在 [MyLocalPath]\\FirstClassController.cs:第 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);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.