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

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

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

Я что-то пропустил?

Версия Entity Framework: 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 ответа

Решение

Настройка 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,

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

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

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

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

context.ChangeTracker.AutoDetectChangesEnabled = false;

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

context.ChangeTracker.AutoDetectChangesEnabled = true;

В соответствии с Entity Framework, статья "Автоматическое обнаружение изменений"

Они сказали:

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

Я заметил огромный прирост производительности, отключив AutoDetectChangesEnabled.

Я добавлял тысячи записей в список, и если отключить эту функцию, время работы увеличилось с часов до нескольких минут.

Другие вопросы по тегам