TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #2927 2.41K
День 2430. #ЗаметкиНаПолях
Управляем Временем Жизни DbContext. Окончание

Начало

Примеры из реального мира
1. Контроллер / Минимальные API (Scoped)
DI даёт вам scoped-контекст, привязанный к запросу. Одна единица работы, никаких утечек:
app.MapGet("/orders/{id:int}", 
async (int id,
AppDbContext db,
CancellationToken ct) =>
{
var order = await db
.Orders.FindAsync([id], ct);

return order is null
? Results.NotFound()
: Results.Ok(order);
});


2. Фоновые сервисы
Фоновые сервисы не имеют области видимости запроса, вы должны создать область видимости:
public sealed class CleanupService(
IServiceScopeFactory scopes,
ILogger<CleanupService> log)
: BackgroundService
{
protected override async Task
ExecuteAsync(CancellationToken stop)
{
while (!stop.IsCancellationRequested)
{
using var scope = scopes.CreateScope();
var db = scope
.ServiceProvider
.GetRequiredService<AppDbContext>();

// Одна короткоживущая единица работы
// … используем db …
await db.SaveChangesAsync(stop);

await Task.Delay(TimeSpan.FromHours(6), stop);
}
}
}


Либо использовать фабрику:
public sealed class CleanupService(
IDbContextFactory<AppDbContext> factory,
ILogger<CleanupService> log)
: BackgroundService
{
protected override async Task
ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
await using var db = await
factory.CreateDbContextAsync(ct);
// … та же логика, что и выше …
}
}
}


3. Синглтон-сервис, которому нужна БД
Синглтоны не должны захватывать DbContext. Создание нового при каждом вызове помогает избежать проблем:
csharp 
public sealed class PricingCache(
IDbContextFactory<AppDbContext> factory,
IMemoryCache cache)
{
public async Task<decimal>
GetPriceAsync(int id, CancellationToken ct)
{
if (cache.TryGetValue(id, out var price))
return price;

await using var db = await
factory.CreateDbContextAsync(ct);
price = await db.Products
.Where(p => p.Id == id)
.Select(p => p.Price)
.FirstAsync(ct);

cache.Set(id, price, TimeSpan.FromMinutes(10));
return price;
}
}


4. Высокопроизводительные APIs (пулинг)
builder.Services
.AddDbContextPool<AppDbContext>(o =>
{
o.UseNpgsql(
builder
.Configuration
.GetConnectionString("Default"));
// Не используйте состояние в опциях
// Избегайте изменяемого состояния
});

Совет: Пулинг улучшает пропускную способность. Он не делает DbContext потокобезопасным. По-прежнему один контекст на запрос.

Распространённые ошибки
1. Совместное использование одного DbContext между потоками
Симптом: "A second operation started on this context before a previous operation was completed." (Вторая операция началась в этом контексте до завершения предыдущей операции).
Решение: один контекст на единицу работы; не выполняйте параллельные запросы в одном и том же контексте.

2. Внедрение DbContext в синглтоны
Решение: внедрение IDbContextFactory или IServiceScopeFactory и создание контекстов по требованию.

3. Долгоживущие контексты
Решение: делайте контексты короткоживущими, иначе раздуваются трекеры изменений и удерживаются соединения.

4. Использование пула с состоянием запросов
Решение: не добавляйте пользовательское состояние к контексту (например, поле CurrentUserId). Контексты в пуле переиспользуются.

5. Попытка «ускорения» путём одновременного выполнения нескольких запросов в одном контексте.
Решение: либо сериализуйте работу, либо создайте несколько контекстов. DbContext не является потокобезопасным.

Итого
Думайте о DbContext как о листке-черновике: вы берёте лист, используете для коротких записей, и выбрасываете его, когда закончите. Не передавайте его по всему офису и не пытайтесь писать на нём двумя ручками одновременно.

Источник: https://thecodeman.net/posts/managing-ef-core-dbcontext-lifetime
  • 👍 28
More from @netdeveloperdiary
  1. Oct 2, 2026День 2802. #Карьера #Юмор Секреты Программирования, Известные Только Легендам Ещё один пос…
  2. Oct 1, 2026Post #3357
  3. Sep 30, 2026Post #3356
  4. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
  5. Sep 29, 2026День 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная ко…
  6. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →