DbContext AutoDetectChangesEnabled设置为false检测更改 [英] DbContext AutoDetectChangesEnabled set to false detecting changes

查看:199
本文介绍了DbContext AutoDetectChangesEnabled设置为false检测更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



我错过了什么?



实体框架版本:5.0.0.0



DbContext类

  public class ProjectContext:DbContext {
public DbSet< Project>项目{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)
{

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

sw.WriteLine();
sw.WriteLine(*** Entity Name:+ name +
处于+状态);
var currentValues = x.CurrentValues;
sw.WriteLine(*** CurrentValues ***);
PrintPropertyValues(currentValues,sw);
if(state!= EntityState.Added)
{
sw.WriteLine(*** Original Values ***);
PrintPropertyValues(x.OriginalValues,sw);
}
}
}
}

日志

  ***实体名称:Models.Projectis处于添加状态
*** CurrentValues ***
ProjectId:0
ProjectName:uniqueName

第二个日志

  ***实体名称:Models.Projectis处于修改状态
*** CurrentValues ***
ProjectId: 1
ProjectName:uniqueName
***原始值***
ProjectId:1
ProjectName:一个不同的名称!


解决方案

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



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



在您的情况下在方法的第一部分中添加状态,即使使用 AutoDetectChangesEnabled 设置为 false ,因为您只调用 db.Projects.Add(p)。 (您的代码btw中缺少该行,但我猜这只是一个复制和粘贴错误。)从 DbContext API调用一个方法可以正确地跟踪更改和在添加之前状态正确的情况下,跟踪器将是正确的。



或者换句话说:调用API方法不会将正确的状态转变为错误的状态。但是,如果 AutoDetectChangesEnabled false 它也不会将错误的状态转变为正确的状态如果 AutoDetectChangesEnabled true



然而,在您的方法的第二部分您正在更改POCO属性值。在这一点之后,更改跟踪器状态是错误的(不变)而不调用 DetectChanges (手动或 - 如果 AutoDetectChangesEnabled true - 自动在 ChangeTracker.Entries SaveChanges )它将永远不会被调整。效果是更改的属性值未保存到数据库。



在最后一节中提到状态不变我指的是我自己的测试(也是我期望的)。我不知道,不能复制为什么你有状态修改



对不起,如果这听起来都是有点混乱亚瑟维克斯可以更好地解释。 a>



我发现自动更改检测和禁用时的行为相当难以理解和掌握,我通常不会触摸默认( = true


I'm a bit stumped. From what I've read setting the DbContext.AutoDetectChangesEnabled to false should disable change tracking requiring one to call DbContext.DetectChanges in order to identify changes to be sent to the database.

However, it is clear from my logs below that the changes are being registered by dbContexts change tracker, even with the setting set to false.

Am I missing something?

Entity Framework Version: 5.0.0.0

DbContext class

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

Controller class

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();
}

Logging method

    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);
                }
            }
        }
    }

First log

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

Second Log

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

解决方案

Setting AutoDetectChangesEnabled to false doesn't disable change tracking. (That's what the AsNoTracking() extension method would do.) It just disables the automatic call of DetectChanges that would otherwise occur in many DbContext API methods.

But DetectChanges isn't the only method that participates in change tracking. However, if you don't call it manually at the right places where it is needed the tracked entity states are incomplete or wrong leading to incorrectly saved data.

In your case the state Added in the first part of your method is expected, even with AutoDetectChangesEnabled set to false because you only call db.Projects.Add(p). (The line is missing in your code btw, but I guess it's just a copy and paste error.) Calling a method from the DbContext API tracks changes correctly and the states in the tracker will be correct if the state was correct before the call to Add.

Or in other words: Calling an API method doesn't turn a correct state into a wrong state. But: If AutoDetectChangesEnabled is false it also won't turn a wrong state into a correct state which would be the case if AutoDetectChangesEnabled is true.

However, in the second part of your method you are just changing a POCO property value. After this point the change tracker state is wrong (Unchanged) and without a call to DetectChanges (manually or - if AutoDetectChangesEnabled is true - automatically in ChangeTracker.Entries or SaveChanges) it will never be adjusted. The effect is that the changed property value is not saved to the database.

In the last section mentioning the state Unchanged I'm refering to my own test (and also to what I would expect). I don't know and can't reproduce why you have state Modified.

Sorry, if this sounds all a bit confusing. Arthur Vickers can explain it better.

I find automatic change detection and the behaviour when disabling it rather difficult to understand and to master and I usually don't touch the default (AutoDetectChangesEnabled = true) for any tracked changes that are more complex than the simplest things (like bulk adding entities in a loop, etc.).

这篇关于DbContext AutoDetectChangesEnabled设置为false检测更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆