Ответ
В Entity Framework Core есть несколько способов отключить механизм отслеживания изменений (change tracking) для сущностей, что полезно для операций только для чтения и повышения производительности.
Основные методы:
-
AsNoTracking()— отключает отслеживание для результатов конкретного запроса.var users = context.Users.AsNoTracking().ToList(); -
AsNoTrackingWithIdentityResolution()— аналогиченAsNoTracking, но обеспечивает разрешение идентичности: если в результате запроса встречается одна и та же сущность (по ключу) несколько раз, будет возвращен один и тот же экземпляр объекта. Это полезно для предотвращения дублирования в графах объектов. -
Глобальная настройка контекста — можно установить поведение по умолчанию для всех запросов данного контекста.
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString) .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));После этого для запросов, требующих отслеживания, нужно явно использовать
.AsTracking(). -
Отсоединение сущности (Detach) — если сущность уже загружена с отслеживанием, её можно отсоединить.
context.Entry(entity).State = EntityState.Detached;
Когда это нужно:
- При выполнении запросов только для чтения (отчеты, экспорт данных).
- При маппинге результатов запроса в DTO или ViewModel.
- В сценариях с кратковременным контекстом (например, в веб-приложениях), когда изменения не планируется сохранять.
Важно: При отключенном отслеживании любые изменения, внесенные в полученные объекты, не будут автоматически сохранены в базу данных при вызове SaveChanges().
Ответ 18+ 🔞
Слушай, а вот эта ваша штука с отслеживанием изменений в Entity Framework — она же, блядь, иногда так жрёт ресурсы, что мама не горюй! Особенно если ты просто данные читаешь, как на параше газетку. Ну, типа отчёты там, или что-то выгружаешь. А он там, сука, за каждым объектом следит, в кэш пихает, состояние меняет — в общем, овердохуища телодвижений.
Так вот, чтобы эту поебень отключить, есть несколько способов. Выбирай, как тебе удобнее.
Первое — точечно, прямо в запросе. Самый частый случай.
var users = context.Users.AsNoTracking().ToList();
Всё, после AsNoTracking() эти юзеры — как чужие трусы. Меняй их сколько влезет, контекст про это нихуя не узнает и в базу ничего не отправит. Производительность сразу подскакивает, потому что EF не строит свой внутренний цирк с конями вокруг каждого экземпляра.
Второе — почти то же самое, но с приколом. Бывает, в результатах запроса одна и та же хрень по ключу встречается несколько раз (ну, в связанных данных). Обычный AsNoTracking() для каждой встречи создаст новый объект в памяти — получишь клонов, как в "Звёздных войнах". Чтобы этого не было, есть AsNoTrackingWithIdentityResolution(). Он такой: "Ага, юзер с ID=1? Я его уже видел, вот, держи ссылку на тот же самый объект". Графы объектов не дублируются, красота.
Третье — глобально, на весь контекст. Если у тебя в проекте 90% запросов — чтение, можно не писать AsNoTracking() в каждом методе, а сказать контексту раз и навсегда: "Не отслеживай нихуя по умолчанию".
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString)
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));
Теперь все запросы будут без отслеживания. А если вдруг в оставшихся 10% нужно что-то изменить и сохранить — явно юзай .AsTracking(). Да, придётся помнить об этом, зато везде, где можно, получишь профит.
Четвёртое — экстренное отсоединение. Бывает, сущность уже в контексте болтается, отслеживается, а тебе надо, чтобы отстала. Ну, например, для каких-то мануальных манипуляций. Тогда делай так:
context.Entry(entity).State = EntityState.Detached;
Всё, контекст про неё забыл. Как будто и не было.
Когда это всё, блядь, нужно?
- Когда только читаешь (отчёты, дашборды, экспорт в Excel). Это главный случай.
- Когда маппишь результаты в DTO или ViewModel. Зачем отслеживать то, во что ты просто копируешь данные?
- В короткоживущих контекстах, типа веб-запроса, где ты чаще всего ничего не меняешь, а просто показываешь данные. Это вообще best practice, между прочим.
И главное предупреждение, нахуй! Если ты взял данные через AsNoTracking(), потом их там поредактировал и вызвал SaveChanges() — нихуя не сохранится! Контекст про эти изменения просто не в курсе. Он за ними не следил. Так что если нужно менять — либо бери с отслеживанием, либо прикрепляй (Attach) и меняй состояние вручную. Не напоминай — сам знаешь.