TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 550 subscribers
Post #528 219
🚫 ءDbContext Thread-Safe نیست: اجرای موازی Queryهای EF Core به روش درست

ما همه یک بار آن endpoint را ساخته‌ایم.

همان Endpoint معروفی که برای Executive Dashboard یا User Summary استفاده می‌شود. جایی که باید چندین مجموعه‌ دادهٔ کاملاً نامربوط را بگیری تا یک تصویر کامل به کاربر نشان بدهی.
مثلاً:
• ۵۰ سفارش آخر
• لاگ‌های سلامت سیستم
• تنظیمات پروفایل کاربر
• تعداد اعلان‌ها

و معمولاً کد را این‌گونه می‌نویسیم:
var orders = await GetRecentOrdersAsync(userId);
var logs = await GetSystemLogsAsync();
var stats = await GetUserStatsAsync(userId);

return new DashboardDto(orders, logs, stats);

این کد کار می‌کند. تمیز است. خواناست. اما یک مشکل جدی وجود دارد. ⚠️
اگر:
🔹️GetRecentOrdersAsync = 300ms
🔹️GetSystemLogsAsync = 400ms
🔹️GetUserStatsAsync = 300ms

کاربر باید ۱ ثانیه کامل منتظر بماند (۳۰۰ + ۴۰۰ + ۳۰۰).

در سیستم‌های توزیع‌شده، Latency تجربهٔ کاربری را نابود می‌کند.
و چون این داده‌ها از هم مستقل هستند، باید بتوانیم آن‌ها را به صورت موازی اجرا کنیم.

اگر این کار را بکنیم، طول کل درخواست = کندترین Query (۴۰۰ms)

یعنی ۶۰٪ بهبود عملکرد فقط با تغییر نحوهٔ اجرای Queryها. 🔥

اما اگر با Entity Framework Core به شکل ساده بخواهی آن‌ها را موازی کنی…
اپلیکیشن Crash می‌کند.

💥 وعدهٔ دروغین Task.WhenAll

رایج‌ترین اشتباه این است که کد را برداری، آن را در چند Task بیندازی و منتظر بمانی:
// ❌ DO NOT DO THIS
public async Task<DashboardData> GetDashboardData(int userId)
{
var ordersTask = _repository.GetOrdersAsync(userId);
var logsTask = _repository.GetLogsAsync();
var statsTask = _repository.GetStatsAsync(userId);

await Task.WhenAll(ordersTask, logsTask, statsTask); // BOOM 💥

return new DashboardData(ordersTask.Result, logsTask.Result, statsTask.Result);
}

اگر این را اجرا کنی، بلافاصله با این Exception روبرو می‌شوی:
A second operation started on this context before a previous operation completed.
This is usually caused by different threads using the same instance of DbContext...

چرا این اتفاق می‌افتد؟ 🤔

❗️چرا DbContext Thread-Safe نیست؟

زیرا DbContext در EF Core stateful است و برای "یک Unit of Work" طراحی شده.

دلایل اصلی:
1️⃣ Change Tracker

ءDbContext وضعیت Entityهایی که بارگذاری شده‌اند را نگه می‌دارد.
دو Thread همزمان نمی‌توانند این وضعیت را تغییر دهند.

2️⃣ Single Database Connection

هر DbContext معمولاً یک Connection دارد.
پروتکل پایگاه‌داده (TCP Stream برای PostgreSQL یا SQL Server) اجازهٔ اجرای هم‌زمان چند Query روی یک Connection را نمی‌دهد.

3️⃣ ءRace Condition و خراب شدن State داخلی

اگر دو Query همزمان اجرا شوند، DbContext نمی‌داند کدام نتیجه مربوط به کدام Query است.

بنابراین EF Core برای جلوگیری از فساد داده، Exception می‌اندازد.

🧩 پس یک تناقض داریم:

می‌خواهیم Queryها را موازی اجرا کنیم
اما EF Core ما را مجبور می‌کند پیاپی اجرا کنیم.

در ادامهٔ مقاله راه‌حل‌های درست معرفی می‌شود…
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 →