DbContext AutoDetectChangesEnabled 设置为 false 检测更改

问题描述 投票:0回答:4

我有点难住了。根据我的阅读,将

DbContext.AutoDetectChangesEnabled
设置为
false
应该禁用更改跟踪,需要调用
DbContext.DetectChanges
才能识别要发送到数据库的更改。

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

我错过了什么吗?

实体框架版本: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
4个回答
68
投票

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

但是

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

在您的情况下,即使

Added
设置为
method
,您的
AutoDetectChangesEnabled
第一部分中的状态
false
也是预期的,因为您只调用
db.Projects.Add(p)
。 (顺便说一句,您的代码中缺少该行,但我猜这只是复制和粘贴错误。)从
DbContext
API 调用方法可以正确跟踪更改,并且如果在之前状态正确,则跟踪器中的状态将是正确的。致电
Add

或者换句话说:调用API方法不会将正确的状态变成错误的状态。但是:如果

AutoDetectChangesEnabled
false
,它也不会将错误状态转变为正确状态,如果
AutoDetectChangesEnabled
true
,就会出现这种情况。

但是,在

method
的第二部分中,您只是更改 POCO 属性值。此后,更改跟踪器状态错误 (
Unchanged
),并且无需调用
DetectChanges
(手动或 - 如果
AutoDetectChangesEnabled
true
- 自动在
ChangeTracker.Entries
SaveChanges
中)它永远不会被调整。效果是更改的属性值不会保存到数据库中。

在最后一节提到状态

Unchanged
我指的是我自己的测试(以及我所期望的)。我不知道也无法重现为什么你有状态
Modified

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

我发现自动更改检测和禁用它时的行为相当难以理解和掌握,并且对于任何比最简单的事情更复杂的跟踪更改,我通常不会触及默认值(

AutoDetectChangesEnabled
=
true
)例如在循环中批量添加实体等)。


33
投票

如果有人在 Entity Framework Core 中寻找

AutoDetectChangesEnabled
,您可以在
ChangeTracker
下找到它,而不是
Configuration

用法如下:

context.ChangeTracker.AutoDetectChangesEnabled = false;

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

context.ChangeTracker.AutoDetectChangesEnabled = true;

9
投票

根据实体框架自动检测变化的文章

他们说:

通过在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
方法时对
SaveChanges
进行不必要的调用。


0
投票

通过关闭 AutoDetectChangesEnabled,我看到了巨大的性能提升。

我在列表中添加了数千条记录,关闭此功能导致运行时间从几小时缩短到几分钟。

© www.soinside.com 2019 - 2024. All rights reserved.