DbContext AutoDetectChangesEnabled设置为false检测更改

时间:2013-05-31 18:13:26

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

我有点难过。根据我的阅读设置,DbContext.AutoDetectChangesEnabledfalse应禁用更改跟踪,要求人们调用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!

3 个答案:

答案 0 :(得分:52)

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

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

在您的情况下,Added的第一部分中的州method是预期的,即使AutoDetectChangesEnabled设置为false,因为您只拨打db.Projects.Add(p) 。 (你的代码btw中缺少这一行,但我想这只是一个复制和粘贴错误。)调用DbContext API中的方法可以正确跟踪更改,如果状态正确,则跟踪器中的状态将是正确的在致电Add之前。

或换句话说:调用API方法不会将正确的状态转换为错误的状态。但是:如果AutoDetectChangesEnabledfalse,它也不会将错误状态转换为正确状态,如果AutoDetectChangesEnabledtrue则会出现这种情况。

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

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

很抱歉,如果这听起来有点令人困惑。 Arthur Vickers can explain it better.

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

答案 1 :(得分:6)

如果有人在实体框架核心中寻找AutoDetectChangesEnabled,您可以在ChangeTracker Configuration

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

用法如:

EvtsUpdated,IR23488670,15920221,ESTIMATED
EvtsUpdated,IR23488676,11014018,ESTIMATED
EvtsUpdated,IR23488700,7273867,ESTIMATED
EvtsUpdated,IR23486360,7273881,ESTIMATED
EvtsUpdated,IR23488670,7273807,ESTIMATED
EvtsUpdated,IR23488670,9738420,ESTIMATED
EvtsUpdated,IR23488670,7273845,ESTIMATED
EvtsUpdated,IR23488676,12149463,ESTIMATED

答案 2 :(得分:5)

根据实体Framework Automatic Detect Changes's Article

他们说:

  通过在1,2,3

中将其关闭,您可能会获得显着的效果改进

从那篇文章中看这个例子

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; } } DetectChanges方法时对DbSet.Add进行不必要的调用。