我一直在尝试创建一个审计跟踪,尝试通过TrackChanges,SaveChanges()的替代以及通过使用DbEntityEntry.OriginalValues来获取实体的原始值的多种方法,最终将这些方法归结为相同的方法问题。当我将另一个模型引用为ICollection时,它不会在实体中记录该模型。
作为此问题的基本说明,请参见以下代码:

public void Update(Project project)
{
    _ctx.OriginalValues(project);
    _ctx.Projects.Attach(project);
    _ctx.Entry(project).State = EntityState.Modified;
    _ctx.SaveChanges(project);
}


上面的.OriginalValues在激活保存更改之前将实体传递给此方法,并且我能够在用户更改之前读取实体中的值。 OriginalValues方法如下所示:

public void OriginalValues(object entity)
{
    var entry = this.Entry(entity);
    System.Reflection.PropertyInfo[] names = entity.GetType().GetProperties();

    foreach (var property in names)
    {
        var n = entry.OriginalValues[property.Name];
    }
}


我理解的上述方法不是很好的方法或最佳实践,但这是从我的实体读取原始值的大量尝试中的最新尝试。

当此代码运行时,property.Name将获得一个名为“ Teams”的名称,该名称在Project模型中被引用为:

public class Project
{
    public int Id { get; set; } // PK
    public string Name { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public int MarketId { get; set; } // FK
    [ForeignKey("MarketId")]
    public Market Market { get; set; } // FK Nav
    public ICollection<Team> Teams { get; set; } // Many to Many Nav
}


抛出一个错误,告诉我它没有映射到Project,即使我曾经使用过流畅的API和数据注释都试图为此进行映射。

这是一个例子,我在其他模型中也有相同的情况,但是有很多对许多的关系。

我是一名研究生开发人员,因此没有太多接触.net的机会,我希望有人可以在此方面提供任何建议或支持!

谢谢

编辑:显示错误消息:


  'Teams'属性不存在或未针对'Project'类型进行映射。
  
  说明:执行当前Web请求期间发生未处理的异常。请查看堆栈跟踪,以获取有关错误及其在代码中起源的更多信息。
  
  异常详细信息:System.ArgumentException:'Teams'属性不存在或未映射为'Project'类型。
  
  源错误:


Line 78:             foreach (var property in names)
Line 79:             {
Line 80:                 var n = entry.OriginalValues[property.Name];
Line 81:
Line 82:             }

最佳答案

出现此错误是因为EF将每个条目的值保存在其自己的对象中,因此导航属性的值将保存在其条目中,因此它们不在当前对象的OriginalValues中。您可以访问导航属性,如下所示:

foreach (var property in names)
{
    var m = entry.Member(property.Name);
    if (m is DbPropertyEntry)//simple property
    {
         var p = entry.Property(property.Name);
    }
    if (m is DbReferenceEntry)//navigation to single object
    {
         var r = entry.Reference(property.Name);
    }
    if (m is DbCollectionEntry)//navigation to collection
    {
         var c = entry.Collection(property.Name);
    }
}


然后,您可以将每个导航对象视为新对象,并获取它们的原始值。

建议:
EF内部有一个跟踪系统,该系统跟踪对对象图所做的所有更改,您可以查询此跟踪系统并记录更改,类似这样。无需跟踪引用,因为如果引用发生更改,则EF会检测到它。

public void OriginalValues(object entity)
{
    ChangeTracker.DetectChanges();
    var changed = ChangeTracker.Entries()
            .Where(x=>x.State != EntityState.Unchanged).ToList();
    foreach (var entry in changed)
    {
        switch (entry.State)
        {
            case EntityState.Added:
                Debug.WriteLine("object of type " + entry.Entity.GetType().Name
                   + "created:");
                foreach(var name in entry.CurrentValues.PropertyNames)
                {
                    Debug.WriteLine(name + " : " + entry.CurrentValues[name]);
                }
            break;
            case EntityState.Deleted:
                Debug.WriteLine("object of type " + entry.Entity.GetType().Name
                   + "deleted:");
                foreach(var name in entry.OriginalValues.PropertyNames)
                {
                    Debug.WriteLine(name + " : " + entry.OriginalValues[name]);
                }
            break;
            case EntityState.Modified:
                Debug.WriteLine("object of type " + entry.Entity.GetType().Name
                   + "updated:");
                Debug.WriteLine("current values:");
                foreach(var name in entry.CurrentValues.PropertyNames)
                {
                    Debug.WriteLine(name + " : " + entry.CurrentValues[name]);
                }
                Debug.WriteLine("original values:");
                foreach(var name in entry.OriginalValues.PropertyNames)
                {
                    Debug.WriteLine(name + " : " + entry.OriginalValues[name]);
                }
            break;
         }
     }
 }


注意:删除对象时,请确保将状态设置为Deleted

10-06 00:38