c# - Entity Framework Code First Auditing 多对多和一对多问题

标签 c# .net entity-framework

我一直在尝试创建一个审计跟踪,尝试通过 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”的名称,该名称在项目模型中被引用:

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 
}

抛出一个错误,告诉我它还没有映射到项目,即使我已经使用流畅的 API 和数据注释来尝试并为此获取映射。

这是一个示例,我在其他模型中遇到了相同的情况,但存在多对多关系。

我是一名研究生开发人员,因此没有大量接触 .net 我希望有人可以在可能的情况下提供任何建议或支持!

谢谢

编辑:显示的错误信息:

The 'Teams' property does not exist or is not mapped for the type 'Project'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentException: The 'Teams' property does not exist or is not mapped for the type 'Project'.

Source Error:

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

关于c# - Entity Framework Code First Auditing 多对多和一对多问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32120315/

相关文章:

c# - 在 C# 中覆盖二元运算符

c# - 根据 IP 将用户重定向到子域

linq - 如何使用 Linq 连接对象和实体?

c# - 实体 IEnumerable 仅获取基类 - 而不是派生类

c# - 无法使用适用于 .NET 的 AWS 开发工具包获取预签名对象 URL

c# - 使用两列的 Linq 查询分组数据表

c# - 为什么在 MySQL 的存储过程中使用 OUT 参数时 ODBC C# 返回空字符串?

python - 如何等待 python 中的任务列表?

c# - MySqlConnection Open() 未打开且未捕获错误

mysql - 部署 - 带有 Entity Framework 的 MySQL