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.
Я добавлял тысячи записей в список, и если отключить эту функцию, время работы увеличилось с часов до нескольких минут.