C# Audit.NET连接对象保存问题

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

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

现在我正在跟踪另一个连接到第一个实体的实体,当我试图保存它时,audit save函数抛出一个反射错误

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函数中得到一个错误

当我在保存时将第二个类引用保留为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
    );