C# Audit.NET连接对象保存问题
我正在使用带有EntityFramework扩展的Audit.NET,当我只跟踪一个实体时,一切都运行良好 现在我正在跟踪另一个连接到第一个实体的实体,当我试图保存它时,audit save函数抛出一个反射错误 System.Reflection.TargetException:“对象与目标类型不匹配。” 我的课程结构如下:C# Audit.NET连接对象保存问题,c#,audit.net,C#,Audit.net,我正在使用带有EntityFramework扩展的Audit.NET,当我只跟踪一个实体时,一切都运行良好 现在我正在跟踪另一个连接到第一个实体的实体,当我试图保存它时,audit save函数抛出一个反射错误 System.Reflection.TargetException:“对象与目标类型不匹配。” 我的课程结构如下: public class FirstClass{ public int ID{get;set;} //Some props here public Second
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函数中得到一个错误
当我在保存时将第二个类引用保留为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;
}))
);
编辑2:堆栈跟踪
位于System.Reflection.RuntimeMethodInfo.CheckConsistency(对象目标)
位于System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(对象对象对象、BindingFlags invokeAttr、绑定器、对象[]参数、CultureInfo区域性)
在System.Reflection.RuntimeMethodInfo.Invoke(对象obj、BindingFlags invokeAttr、绑定器绑定器、对象[]参数、CultureInfo区域性)
位于System.Reflection.RuntimePropertyInfo.GetValue(对象obj,对象[]索引)
位于Audit.EntityFramework.Providers.EntityFrameworkDataProvider.CreateAuditEntity(类型definingType,类型auditType,事件条目)
位于Audit.EntityFramework.Providers.EntityFrameworkDataProvider.InsertEvent(AuditEvent AuditEvent)
位于Audit.Core.AuditScope.SaveEvent(布尔forceInsert)
在Audit.Core.AuditScope.Save()处
位于Audit.EntityFramework.DbContextHelper.SaveScope(IAuditDbContext上下文、AuditScope范围、EntityFrameworkEvent事件)
在Audit.EntityFramework.DbContextHelper.SaveChanges(IAuditDbContext上下文,Func`1 baseSaveChanges)处
在[MyLocalPath]\MyDbContext.cs:第132行中的MyDbContext.SaveChanges()处
在[MyLocalPath]\FirstClassRepository.cs:第209行中的FirstClassRepository.UpdateFirstClass类(Int32 id,FirstClassDto first)
在[MyLocalPath]\FirstClassManager.cs:第244行中的FirstClassManager.UpdateFirstClass(Int32 id,FirstClassDto dto)处
在[MyLocalPath]\FirstClassController.cs:第249行中的FirstClassController.c__显示class20_0.b__0()
编辑:
在反复修改之后,我得到了一个错误,通过在映射中添加“MySpecialClass”来说明它是什么类型
System.ArgumentException:'类型为'MySpecialClass'的对象无法转换为类型为'AuditMySpecialClass'
这个类是我的datacontext中的一个类,这可能与它有关,也许不是
现在,错误似乎在到达用户定义的操作之前抛出,您可以将其添加到映射中,可能Audit.NET正在尝试在用户定义的操作之前映射这些内容?因此,我找到了一个解决方案。这不是我想要的100%,但它是有效的 问题在于我的“MySpecialClass”对象是EFCore拥有的类型,它们生成了自己的独立事件,这让Audit.NET感到困惑 因此,我在“MySpecialClass”声明上方添加了[Auditiongnore],并在配置中添加了IgnoreMatchedProperties
[AuditIgnore]
public class MySpecialClass
{
public Unit? UnitOfMeasure { get; set; }
public float? Value { get; set; }
}
使用(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
);
Audit.Core.Configuration.Setup()
.UseEntityFramework(ef=>ef
.AuditTypeExplicitMapper(m=>m
.Map((第一个,审计第一个)=>
{
auditFrst.Tag=frst.Installation.Tag;
})
.Map()
.AuditEntityAction((ev、ent、auditEntity)=>
{
((AuditClass)auditEntity.AuditMessage=ent.Action;
}))
.IgnoreMatchedProperties(t=>t==typeof(FirstClassAudit))//我想我们需要一个更完整的代码示例,最好是一个。我认为我们现在没有足够的。至少包括您的配置调用(Audit.Core.configuration.Setup()
Audit.EntityFramework.configuration.Setup()
),保存函数和完整的stacktrace.include Helper.SaveChanges(@Seabizkit Helper.SaveChanges是Audit.NET的一部分,我无法控制它包括FirstClassAudit
和SecondClassAudit
的代码我想在你的类和你的Audit类之间有一个名称相同但类型不同的属性。我创建它是为了跟踪更改,以允许忽略某些类上的属性匹配类型,而不是上下文范围。
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()
);
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);
}
}
}
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
);