Как отключить отслеживание изменений в Entity Framework
Что проверяют
Понимаете ли вы, что делает трекер изменений в EF Core и чем вы за него платите. AsNoTracking() знают почти все, поэтому следом спрашивают, как потом обновить такую сущность и чем отключение трекинга отличается от отключения AutoDetectChanges.
Как отвечать
При обычном запросе EF Core регистрирует каждую загруженную сущность в ChangeTracker и хранит снимок её исходных значений, чтобы при SaveChanges() понять, что поменялось. Для чтения без записи это лишние аллокации и время.
Способы отключить:
- на запрос:
context.Orders.AsNoTracking().Where(...).ToListAsync(). Основной вариант для списков и отчётов; - с разрешением идентичности:
AsNoTrackingWithIdentityResolution()не отслеживает сущности, но одна и та же запись в результате остаётся одним объектом. Полезно приInclude, где родитель повторяется у многих дочерних записей; - на весь контекст:
optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)при регистрации илиChangeTracker.QueryTrackingBehaviorу экземпляра. Отдельный запрос возвращается к трекингу черезAsTracking(); - проекция:
Select(o => new OrderDto { ... })в DTO не отслеживается вовсе и заодно тянет из базы только нужные колонки.
ChangeTracker.AutoDetectChangesEnabled = false не отключает трекинг, а выключает автоматический поиск изменений, что ускоряет массовое добавление. ChangeTracker.Clear() отсоединяет всё разом. ExecuteUpdate и ExecuteDelete в EF Core 7 и новее меняют данные одним SQL без загрузки сущностей.
Где спотыкаются
Меняют свойства у сущности из AsNoTracking() и вызывают SaveChanges(). Контекст о ней не знает, в базу ничего не уходит, ошибки тоже нет. Нужен Attach с пометкой изменённых свойств или Update, который пометит изменёнными все колонки.
Вызывают Update для отсоединённой сущности, когда в контексте уже отслеживается экземпляр с тем же ключом. EF бросает InvalidOperationException о конфликте ключей.
Ставят NoTracking на весь контекст в приложении, где много записи, а потом ищут по всему коду несохранённые изменения. Глобальная настройка оправдана для отдельного контекста, который только читает.