【问题标题】:DbContext AutoDetectChangesEnabled set to false detecting changesDbContext AutoDetectChangesEnabled 设置为 false 检测更改
【发布时间】:2013-05-27 15:14:16
【问题描述】:

我有点难过。从我读到的将DbContext.AutoDetectChangesEnabled 设置为false 应该禁用更改跟踪,需要调用DbContext.DetectChanges 以识别要发送到数据库的更改。

但是,从我下面的日志中可以清楚地看出,dbContexts 更改跟踪器正在注册更改,即使设置设置为 false。

我错过了什么吗?

实体框架版本:5.0.0.0

DbContext 类

public class ProjectContext : DbContext {
    public DbSet<Project> Projects {get;set;}
}

控制器类

private ProjectContext db = new ProjectContext();

public method(){
    Project p = new Project("uniqueName");
    db.Configuration.AutoDetectChangesEnabled = false;
    db.Projects.Add(p);
    DebugChangeTracker();
    db.SaveChanges();

    db.Projects.First().ProjectName = "a differentName!";
    DebugChangeTracker();
    db.SaveChanges();
}

记录方法

    private void DebugChangeTracker()
    {
        var path = "C:\\mypath\\";
        path = path + Util.GetMsSinceEpoch().ToString() + "changeTracker.log";

        using (StreamWriter sw = new StreamWriter(path))
        {
            var changeTracker = db.ChangeTracker;
            var entries = changeTracker.Entries();
            foreach (var x in entries)
            {

                var name = x.Entity.ToString();
                var state = x.State;

                sw.WriteLine("");
                sw.WriteLine("***Entity Name: " + name +
                             "is in a state of " + state);
                var currentValues = x.CurrentValues;
                sw.WriteLine("***CurrentValues***");
                PrintPropertyValues(currentValues,sw);
                if (state != EntityState.Added)
                {
                    sw.WriteLine("***Original Values***");
                    PrintPropertyValues(x.OriginalValues,sw);
                }
            }
        }
    }

第一个日志

***Entity Name: Models.Projectis in a state of Added
***CurrentValues***
ProjectId:0
ProjectName:uniqueName

第二个日志

***Entity Name: Models.Projectis in a state of Modified
***CurrentValues***
ProjectId:1
ProjectName:uniqueName
***Original Values***
ProjectId:1
ProjectName:a differentName!

【问题讨论】:

    标签: entity-framework entity-framework-5 dbcontext


    【解决方案1】:

    AutoDetectChangesEnabled 设置为false 不会禁用更改跟踪。 (这就是 AsNoTracking() 扩展方法会做的事情。)它只是禁用了 DetectChanges 的自动调用,否则会在许多 DbContext API 方法中发生。

    DetectChanges 并不是参与变更跟踪的唯一方法。但是,如果您没有在需要它的正确位置手动调用它,则跟踪的实体状态不完整或错误,从而导致数据保存不正确。

    在您的情况下,method 的第一部分中的状态Added 是预期的,即使将AutoDetectChangesEnabled 设置为false,因为您只调用db.Projects.Add(p)。 (顺便说一句,您的代码中缺少该行,但我想这只是一个复制和粘贴错误。)从DbContext API 调用方法会正确跟踪更改,如果在致电Add

    或者换句话说:调用 API 方法不会将正确的状态变成错误的状态。但是:如果AutoDetectChangesEnabledfalse,它也不会将错误的状态变成正确的状态,如果AutoDetectChangesEnabledtrue 就是这种情况。

    但是,在 method 的第二部分中,您只是更改了 POCO 属性值。在这一点之后,更改跟踪器状态错误(Unchanged)并且没有调用DetectChanges(手动或 - 如果AutoDetectChangesEnabledtrue - 自动在ChangeTracker.EntriesSaveChanges 中)它将永远不会被调整.效果是改变的属性值没有保存到数据库中。

    在提到状态Unchanged 的最后一节中,我指的是我自己的测试(以及我所期望的)。我不知道也无法重现您为什么拥有Modified 状态。

    对不起,如果这听起来有点混乱。 Arthur Vickers can explain it better.

    我发现自动更改检测和禁用时的行为很难理解和掌握,对于任何比最简单的更复杂的跟踪更改,我通常不会触及默认值 (AutoDetectChangesEnabled = true)事情(比如在循环中批量添加实体等)。

    【讨论】:

    • 我不得不读了几次,但这确实有助于回答我的问题,谢谢!抱歉复制和粘贴错误;我会为后代更新问题。
    • 不幸的是,“在循环中批量添加实体”是您希望禁用更改跟踪的时候。这是一个 massive 加速(样本大小为 1,在我的应用程序中进行了测试,但它是两次运行添加约 3000 行之间的唯一区别)。
    • @EdS.:批量添加是“最简单的事情”之一,我的意思是我实际上禁用自动更改检测。
    • 如何模拟它?
    【解决方案2】:

    如果有人在 Entity Framework Core 中寻找 AutoDetectChangesEnabled,您可以在 ChangeTracker insted of Configuration 下找到它

    用法如下:

    context.ChangeTracker.AutoDetectChangesEnabled = false;
    
    //Do something here
    context.PriceRecords.Add(newPriceRecord);
    
    context.ChangeTracker.AutoDetectChangesEnabled = true;
    

    【讨论】:

    • 谢谢,正是我想要的。
    • 在配置中搜索了这么多小时。谢谢。
    【解决方案3】:

    根据实体Framework Automatic Detect Changes's Article

    他们说:

    您可以通过在some cases

    关闭来获得显着的性能改进

    看看那篇文章中的这个例子

    using (var context = new BloggingContext()) 
    { 
        try 
        { 
            context.Configuration.AutoDetectChangesEnabled = false; 
    
            // Make many calls in a loop 
            foreach (var blog in aLotOfBlogs) 
            { 
                context.Blogs.Add(blog); 
            } 
        } 
        finally 
        { 
            context.Configuration.AutoDetectChangesEnabled = true; 
        }
    }
    

    此代码避免了在调用DbSet.AddSaveChanges 方法时对DetectChanges 的不必要调用。

    【讨论】:

    • 如果你在 finally 块中重新打开它,它是否会自动执行如果它已经打开但更快的操作?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多