TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 550 subscribers
Post #529 208
✅ راه‌حل

از NET 5. به بعد، EF Core دقیقاً برای همین سناریو یک راه‌حل درجه‌یک ارائه داده:
IDbContextFactory<T> 🎉

به‌جای تزریق یک DbContext با طول عمر Scoped (که برای کل Request زنده می‌ماند)، یک Factory تزریق می‌کنیم که هر زمان لازم شد یک DbContext سبک، مستقل و بدون تداخل بسازد.

این یعنی:
هر Task → یک DbContext مستقل → یک Connection مستقل → بدون هیچ Conflict👌

💡نکته:

اگر به DbContextOptions دسترسی داری، حتی می‌توانی دستی هم Context بسازی:
using var context = new AppDbContext(options);


🛠 ثبت Factory در Program.cs

ء<IDbContextFactory<AppDbContext به صورت Singleton رجیستر می‌شود و خود AppDbContext همچنان به صورت Scoped قابل استفاده است
builder.Services.AddDbContextFactory<AppDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString("db"));
});


⚡️ ءRefactor کردن Dashboard برای اجرای موازی

به‌جای اینکه AppDbContext را تزریق کنیم، <IDbContextFactory<AppDbContext را تزریق می‌کنیم.

در هر Task:
1️⃣ یک DbContext جدید می‌سازیم
2️⃣ ءQuery را اجرا می‌کنیم
3️⃣ آن را Dispose می‌کنیم

بدون هیچ تداخلی 🔥
using Microsoft.EntityFrameworkCore;

public class DashboardService(IDbContextFactory<AppDbContext> contextFactory)
{
public async Task<DashboardDto> GetDashboardAsync(int userId)
{
// 1. اجرای موازی تمام Query ها
var ordersTask = GetOrdersAsync(userId);
var logsTask = GetSystemLogsAsync();
var statsTask = GetUserStatsAsync(userId);

// 2. صبر برای اتمام همه
await Task.WhenAll(ordersTask, logsTask, statsTask);

// 3. برگرداندن نتایج
return new DashboardDto(
await ordersTask,
await logsTask,
await statsTask
);
}

private async Task<List<Order>> GetOrdersAsync(int userId)
{
await using var context = await contextFactory.CreateDbContextAsync();

return await context.Orders
.AsNoTracking()
.Where(o => o.UserId == userId)
.OrderByDescending(o => o.CreatedAt)
.ThenByDescending(o => o.Amount)
.Take(50)
.ToListAsync();
}

private async Task<List<SystemLog>> GetSystemLogsAsync()
{
await using var context = await contextFactory.CreateDbContextAsync();

return await context.SystemLogs
.AsNoTracking()
.OrderByDescending(l => l.Timestamp)
.Take(50)
.ToListAsync();
}

private async Task<UserStats?> GetUserStatsAsync(int userId)
{
await using var context = await contextFactory.CreateDbContextAsync();

return await context.Users
.Where(u => u.Id == userId)
.Select(u => new UserStats { OrderCount = u.Orders.Count })
.FirstOrDefaultAsync();
}
}


🧠 مفاهیم کلیدی

1️⃣ جداسازی کامل Contextها 🧩

هر Task → یک DbContext مستقل
یعنی:
• یک Connection جدا
• بدون رقابت روی Change Tracker
• بدون Race Condition
• بدون Exception خطرناک EF Core

2️⃣ ءDispose شدن سریع Context 🧹
با await using، Context فوراً Dispose می‌شود و Connection به Connection Pool برمی‌گردد.
این نکته حیاتی است، مخصوصاً زیر بار بالا.
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
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 →