DbContext AutoDetectChangesEnabled настроен на ложное обнаружение изменений

Я немного озадачен. Из того, что я прочитал, установка DbContext.AutoDetectChangesEnabled на false должна отключить отслеживание изменений, требующее вызова DbContext.DetectChanges для определения изменений, которые должны быть отправлены в базу данных.

Однако из моих журналов ниже видно, что изменения регистрируются средством отслеживания изменений dbContexts, даже если для параметра установлено значение false.

Я что-то упускаю?

Версия Entity Framework: 5.0.0.0

класс ДбКонтекст

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!

person Jesse    schedule 31.05.2013    source источник


Ответы (3)


Установка AutoDetectChangesEnabled на false не отключает отслеживание изменений. (Это то, что будет делать метод расширения AsNoTracking().) Он просто отключает автоматический вызов DetectChanges, который в противном случае возникал бы во многих методах DbContext API.

Но DetectChanges — не единственный метод, участвующий в отслеживании изменений. Однако, если вы не вызываете его вручную в нужных местах, где это необходимо, состояния отслеживаемых объектов будут неполными или неправильными, что приведет к неправильному сохранению данных.

В вашем случае ожидается состояние Added в первой части вашего method, даже если AutoDetectChangesEnabled установлено на false, потому что вы вызываете только db.Projects.Add(p). (Кстати, эта строка отсутствует в вашем коде, но я предполагаю, что это просто ошибка копирования и вставки.) Вызов метода из API DbContext корректно отслеживает изменения, и состояния в трекере будут правильными, если состояние было правильным до вызова Add.

Или, другими словами: вызов метода API не превращает правильное состояние в неправильное. Но: если AutoDetectChangesEnabled равно false, это также не превратит неправильное состояние в правильное состояние, которое было бы в случае, если AutoDetectChangesEnabled равно true.

Однако во второй части вашего method вы просто меняете значение свойства POCO. После этой точки состояние отслеживания изменений неверно (Unchanged) и без вызова DetectChanges (вручную или, если AutoDetectChangesEnabled равно true, автоматически в ChangeTracker.Entries или SaveChanges), оно никогда не будет скорректировано. В результате измененное значение свойства не сохраняется в базе данных.

В последнем разделе, где упоминается состояние Unchanged, я имею в виду свой собственный тест (а также то, что я ожидал). Я не знаю и не могу воспроизвести, почему у вас состояние Modified.

Извините, если это звучит немного запутанно. Артур Викерс может объяснить это лучше.

Я нахожу автоматическое обнаружение изменений и поведение при его отключении довольно сложным для понимания и освоения, и я обычно не трогаю значение по умолчанию (AutoDetectChangesEnabled = true) для любых отслеживаемых изменений, которые являются более сложными, чем самые простые вещи (например, массовое добавление объектов в петля и др.).

person Slauma    schedule 31.05.2013

Если кто-то ищет AutoDetectChangesEnabled в Entity Framework Core, вы можете найти его в разделе ChangeTracker вместо Configuration.

Использование как:

context.ChangeTracker.AutoDetectChangesEnabled = false;

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

context.ChangeTracker.AutoDetectChangesEnabled = true;
person Jiri Houzvicka    schedule 27.07.2017
comment
Спасибо, именно то, что я искал. - person Daniel; 03.06.2019
comment
Искал это внутри Конфигурации так много часов. Спасибо. - person Sagar Khatri; 14.03.2021

в соответствии с статьей организации "Автоматическое обнаружение изменений платформы"

Они сказали:

вы можете добиться значительного повышения производительности, отключив его отключив в 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.

person Basheer AL-MOMANI    schedule 06.10.2016
comment
Если вы снова включите его в блоке finally, сделает ли он автоматически то, что сделал бы, если бы был включен, но быстрее? - person Ian Warburton; 03.10.2017