我使用的是带有Audit.NET扩展的EntityFramework,当我只跟踪一个实体时,一切都很好。
现在我也在跟踪另一个连接到第一个实体的实体,当我试图保存它时,审计保存函数抛出一个反射错误
System.Reflection.TargetException:“Object与目标类型不匹配。”
我的班级结构是这样的:
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
}然后省略对SecondClass在FirstClassAudit中的引用。
我的两个类都在DbContext中,每个审计类都映射到一个单独的表中。我在AuditTypeExplicitMapper下为两个类添加了映射,我在没有问题的情况下调试了这两个类。但是在SaveChanges函数上仍然有一个错误
当我将SecondClass引用保留为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:堆栈跟踪
(在System.Reflection.RuntimeMethodInfo.CheckConsistency(Object目标)在System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj,BindingFlags invokeAttr,binder粘合剂,Object[]参数,CultureInfo培养)在System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,binder粘合剂,Object[]参数,CultureInfo培养)在System.Reflection.RuntimePropertyInfo.GetValue(Object obj,Object[]索引)在Audit.EntityFramework.Providers.EntityFrameworkDataProvider.CreateAuditEntity(Type definingType,auditType类型,( Audit.EntityFramework.Providers.EntityFrameworkDataProvider.InsertEvent(AuditEvent auditEvent)在Audit.Core.AuditScope.SaveEvent(布尔forceInsert) at Audit.Core.AuditScope.Save() at Audit.Core.AuditScope.Save(),AuditScope范围,EntityFrameworkEvent事件在Audit.EntityFramework.DbContextHelper.SaveChanges(IAuditDbContext上下文中,Func`1‘1 baseSaveChanges( MyDbContext.SaveChanges() at MyDbContext.SaveChanges() at FirstClassRepository.UpdateFirstClass(Int32 id,Int32 id,( FirstClassController.<>c__DisplayClass20_0.b__0() at FirstClassManager.UpdateFirstClass(Int32 id,FirstClassDto dto) MyLocalPath\FirstClassManager.cs:line 244 at MyLocalPath\FirstClassController.cs:line 249
编辑:在修改了更多之后,通过在映射中添加“MySpecialClass”,我得到了一个错误,可以说明它是哪种类型
System.ArgumentException:'MySpecialClass‘类型的对象不能转换为’AuditMySpecialClass‘类型。“
这个类是我的数据文本中的一个拥有类型,这可能与它有关,也许不是。
现在,错误似乎在您可以添加到映射中的用户定义操作之前抛出,可能是Audit.NET试图在用户定义的操作之前映射这些操作吗?
发布于 2020-01-20 11:26:06
所以我找到了解决办法。这不是我想要的100%,但它是有效的。
问题是,当我的"MySpecialClass“对象与EFCore一起拥有类型时,它们生成了自己的独立事件,这使Audit.NET感到困惑。
因此,我在"MySpecialClass“声明的前面添加了IgnoreMatchedProperties,并将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);
}
}
}发布于 2020-01-20 20:34:55
使用最新版本的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
);https://stackoverflow.com/questions/59752454
复制相似问题