54

我有点难过。从我读到的设置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!
4

3 回答 3

66

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

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

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

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

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

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

抱歉,如果这听起来有点令人困惑。Arthur Vickers 可以更好地解释它。

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

于 2013-05-31T20:39:40.227 回答
27

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

用法如:

context.ChangeTracker.AutoDetectChangesEnabled = false;

//Do something here
context.PriceRecords.Add(newPriceRecord);

context.ChangeTracker.AutoDetectChangesEnabled = true;
于 2017-07-27T09:44:12.053 回答
8

根据 Entity Framework Automatic Detect Changes 的文章

他们说:

您可以通过将其关闭来获得显着的性能改进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; 
    }
}

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

于 2016-10-06T13:04:40.980 回答