Для чего используется метод AsNoTracking в Entity Framework
Что проверяют
Понимаете ли вы, как устроен трекер изменений в EF Core, а не просто помните, что AsNoTracking «ускоряет». Следом почти всегда спрашивают, что будет, если изменить такую сущность и вызвать SaveChanges, и чем отличается AsNoTrackingWithIdentityResolution.
Как отвечать
По умолчанию запрос в EF Core отслеживаемый: каждая загруженная сущность регистрируется в ChangeTracker контекста вместе со снимком исходных значений. При SaveChanges EF сравнивает текущие значения со снимком и генерирует UPDATE только по изменённым полям. Заодно работает identity resolution: одна строка базы в рамках контекста всегда даёт один и тот же объект.
AsNoTracking() отключает всё это для конкретного запроса:
- меньше работы и памяти: не создаются записи в трекере и снимки, поэтому чтение большого списка для отчёта или API на чтение обходится дешевле;
- нет связи с контекстом: изменения объекта
SaveChangesне увидит, сущность придётся прикрепить черезUpdate()илиAttach()с явной установкой состояния; - нет identity resolution: при
Includeодна и та же связанная запись может прийти несколькими разными объектами. Если это мешает, естьAsNoTrackingWithIdentityResolution().
Для сервиса, который в основном читает, режим можно включить на весь контекст через UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking), а там, где нужна запись, явно вызывать AsTracking().
Стоит добавить, что проекция в DTO через Select сущности и так не отслеживает, AsNoTracking там ничего не меняет. Отслеживаются только экземпляры типов сущностей из модели.
Где спотыкаются
Загружают данные с AsNoTracking, меняют поле и вызывают SaveChanges. Ошибки нет, изменений в базе тоже нет.
Прикрепляют неотслеживаемую сущность через Attach к контексту, где уже отслеживается объект с тем же ключом, и получают InvalidOperationException: второй экземпляр с тем же ключом контекст не примет.
Вешают AsNoTracking на всё подряд как универсальную оптимизацию. На запросе в пару строк выигрыш незаметен, а на графе с Include без identity resolution объектов в памяти может стать больше, а не меньше.