بذار دقیق و آموزشی برات توضیح بدم که آیا استفاده از .Include() در کنار صفحهبندی باعث بارگذاری دادههای حجیم میشه یا نه، و چطور باید باهاش برخورد کرد.
---
✅ پاسخ کوتاه:
اگر از .Include() در صفحهبندی با تعداد بالا (مثل ۱۰۰ آیتم در هر صفحه) استفاده کنی، ممکنه دادههای مرتبط زیادی هم همزمان بارگذاری بشن و باعث سنگین شدن حافظه و کندی عملکرد بشه.
اما این بستگی داره به تعداد و نوع دادههای مرتبط، و اینکه آیا واقعاً به همه اونها در همون لحظه نیاز داری یا نه.
---
🔍 چرا این اتفاق میافته؟
وقتی از .Include() استفاده میکنی، EF Core یک کوئری SQL میسازه که اطلاعات موجودیت اصلی و تمام دادههای مرتبط رو همزمان میگیره.
اگر مثلاً ۱۰۰ نوبت در صفحه داری و هر نوبت یک بیمار و یک خدمت مرتبط داره، EF Core باید:
- ۱۰۰ رکورد از جدول Appointments
- ۱۰۰ رکورد از جدول Patients
- ۱۰۰ رکورد از جدول LabServices
رو همزمان بارگذاری کنه. اگر دادههای مرتبط حجیم باشن (مثلاً عکس، توضیحات طولانی، یا روابط چندلایه)، این میتونه سنگین بشه.
---
⚠️ مشکل اصلی
- افزایش حجم حافظه مصرفی
- کند شدن زمان پاسخدهی
- احتمال بروز خطا در سرورهای محدود منابع
---
🎯 راهحلهای پیشنهادی
1. کاهش تعداد آیتمها در هر صفحه
مثلاً بهجای ۱۰۰، از ۲۰ یا ۳۰ آیتم استفاده کن تا بارگذاری سبکتر بشه.
2. استفاده از Select برای گرفتن فقط فیلدهای موردنیاز
بهجای .Include()، میتونی فقط فیلدهایی که لازم داری رو با Select بگیری:
csharp var data = _context.Appointments .Select(a => new { a.Id, a.Date, PatientName = a.Patient.FullName, ServiceTitle = a.LabService.Title }) .Skip(pageIndex * pageSize) .Take(pageSize) .ToList();3. استفاده از Explicit Loading فقط برای رکوردهایی که نیاز دارن مثلاً وقتی کاربر روی «جزئیات» کلیک کرد، اون موقع دادههای مرتبط رو بارگذاری کن. --- ✅ نتیجهگیری آموزشی ۱ـ .Include() وقتی تعداد آیتمها کم باشه یا دادههای مرتبط سبک باشن ۲ـ Select() وقتی فقط چند فیلد از دادههای مرتبط لازم داری ۳ـ Explicit Loading وقتی فقط در شرایط خاص به دادههای مرتبط نیاز داری
بیایم با یک مثال واقعی از پروژه EFCoreDemo ببینیم چطور میتونیم با استفاده از Explicit Loading دادههای حجیم رو کنترل کنیم تا هم عملکرد بهتر بشه، هم حافظه کمتر مصرف بشه.
---
🎯 سناریو: نمایش جزئیات یک نوبت آزمایشگاهی
فرض کن جدول Appointments شامل اطلاعات نوبتهاست، و هر نوبت به یک Patient و یک LabService مرتبطه.
حالا میخوای در اکشن Details فقط اطلاعات نوبت رو نشون بدی، و فقط در صورت نیاز دادههای مرتبط رو بارگذاری کنی.
---
✅ مثال با Explicit Loading برای کنترل دادههای حجیم
csharp
public async Task<IActionResult> Details(int id)
{
// فقط نوبت اصلی بارگذاری میشود
var appointment = await _context.Appointments
.FirstOrDefaultAsync(a => a.Id == id);
if (appointment == null)
return NotFound();
// بررسی اینکه آیا کاربر درخواست دادههای مرتبط کرده یا نه
if (Request.Query["loadRelated"] == "true")
{
// بارگذاری دستی دادههای مرتبط فقط در صورت نیاز
await _context.Entry(appointment).Reference(a => a.Patient).LoadAsync();
await _context.Entry(appointment).Reference(a => a.LabService).LoadAsync();
}
return View(appointment);
}
---
🔍 مزایای این روش
- کنترل کامل روی زمان و نوع بارگذاری دادهها
- جلوگیری از بارگذاری غیرضروری دادههای حجیم (مثلاً عکس بیمار، توضیحات خدمت)
- بهینهسازی عملکرد در صفحات جزئیات یا گزارشها
- امکان بارگذاری مرحلهای بر اساس نیاز کاربر (مثلاً با دکمه «نمایش اطلاعات بیشتر»)
---
💡 نکته آموزشی
در پروژههای واقعی، دادههای مرتبط مثل عکسها، فایلها، یا توضیحات طولانی ممکنه حجم زیادی داشته باشن.
با استفاده از Explicit Loading، میتونی فقط زمانی که کاربر واقعاً به اون دادهها نیاز داره، اونها رو بارگذاری کنی.
این کار باعث میشه هم سرور سبکتر کار کنه، هم تجربه کاربری بهتر بشه.CProduct.zip
حجم:
24.9M
این پروژه یک سیستم ساده مدیریت محصولات و دستهبندیهاست
پروژه ASP.Net Core MVC (وب و سی شارپ)
این پروژه یک سیستم ساده مدیریت محصولات و دستهبندیهاست
در ادامه، پروژهات رو فقط بهصورت لیست توضیح میدم که چه کارهایی انجام میده و چرا تصمیم گرفتی از Select() بهجای Include() استفاده کنی:
✅ عملکردهای پروژه
- نمایش دستهبندیها با محصولات اخیر هر دسته
- صفحهبندی پویا برای دستهبندیها و محصولات
- نمایش جزئیات محصولات هر دستهبندی
- افزودن، ویرایش و حذف محصولات
- افزودن، ویرایش و حذف دستهبندیها
- نمایش تعداد محصولات مرتبط با هر دسته
- استفاده از ViewModel برای ارسال داده ترکیبی
- طراحی ساده و واکنشگرا با لیستهای Bootstrap
- لینکدهی بین صفحات با asp-controller و asp-action
- جلوگیری از خطاهای dynamic با تعریف دقیق مدلها
🎯 هدف آموزشی پروژه
- آموزش Entity Framework Core و رابطهها
- تمرین معماری MVC در ASP.NET Core
- یادگیری صفحهبندی و ارسال داده به ویو
- تمرین طراحی رابط کاربری ساده و قابل فهم
- ساخت پروژه قابل توسعه برای کلاس، آموزشگاه یا گیتهاب
🔍 چرا از Select() بهجای Include() استفاده کردی
- کنترل دقیق روی فیلدهای مورد نیاز
- کاهش حجم دادههای دریافتی از دیتابیس
- جلوگیری از بارگذاری اضافی موجودیتهای مرتبط
- افزایش سرعت و بهینهسازی کوئریها
- سادهسازی دادهها برای ارسال به ویو
- سازگاری بهتر با ViewModel و ساختار آموزشی پروژه
زمان:
حجم:
19.6M
بهینه سازی کار با داده در ASP.Net Core MVC
ساخته شده از هوش مصنوعی
نکته: شاید پادکست تکراری باشد ولی نکته مهمی گفته شده
پروژه ASP.Net Core MVC (وب و سی شارپ)
بهینه سازی کار با داده در ASP.Net Core MVC ساخته شده از هوش مصنوعی نکته: شاید پادکست تکراری باشد و
بیا این رو به شکل یک اسکریپت پادکست آموزشی آماده کنیم که هم شنیدنی باشه، هم پر از مثال عملی. این متن رو میتونی هم برای ضبط صدا استفاده کنی، هم بعداً به عنوان یادداشت آموزشی نگه داری.
---
🎧 عنوان پادکست:
«سه روش بارگذاری داده در EF Core + Select برای لیست کردن آیتمها + صفحهبندی در ASP.NET Core MVC»
---
🎙️سلام امروز میخوایم با هم سه روش بارگذاری داده در EF Core رو یاد بگیریم، بعد با Select فقط فیلدهای لازم رو بگیریم، و در نهایت با صفحهبندی (Pagination) حجم داده رو کنترل کنیم تا پروژههامون سریعتر و بهینهتر بشه.
---
🧩 بخش اول: سه روش بارگذاری داده در EF Core
1️⃣ Eager Loading – بارگذاری پیشگیرانه
- با Include() دادههای مرتبط رو همزمان با داده اصلی میآریم.
- مثال:
csharp var products = _context.Products .Include(p => p.Category) .ToList();📌 مزیت: فقط یک کوئری به دیتابیس 📌 عیب: ممکنه داده زیادی بیاد که لازم نداشته باشیم --- 2️⃣ Lazy Loading – بارگذاری تنبل - دادههای مرتبط فقط وقتی لود میشن که بهشون دسترسی پیدا کنیم. - نیاز به virtual و فعالسازی UseLazyLoadingProxies():
csharp var product = _context.Products.First(); var categoryName = product.Category.Name; // اینجا کوئری جدا اجرا میشه📌 مزیت: فقط داده لازم لود میشه 📌 عیب: خطر N+1 Query --- 3️⃣ Explicit Loading – بارگذاری صریح - خودمون به صورت دستی و در زمان دلخواه داده مرتبط رو لود میکنیم:
csharp var category = _context.Categories.First(); _context.Entry(category) .Collection(c => c.Products) .Load();📌 مزیت: کنترل کامل روی زمان و نوع بارگذاری 📌 عیب: نیاز به کدنویسی بیشتر --- 🧩 بخش دوم: استفاده از Select برای لیست کردن آیتمها گاهی همهی ستونها رو لازم نداریم. با Select فقط فیلدهای موردنیاز رو میگیریم:
csharp var productList = _context.Products .Select(p => new { p.Title, p.Price }) .ToList();📌 مزیت: حجم داده کمتر → سرعت بیشتر --- 🧩 بخش سوم: صفحهبندی برای کنترل حجم داده فرمول اصلی:
csharp int pageSize = 10; int pageNumber = 2; int skipCount = (pageNumber - 1) * pageSize;کوئری:
csharp var products = _context.Products .AsNoTracking() .Include(p => p.Category) .OrderBy(p => p.Title) .Skip(skipCount) .Take(pageSize) .ToList();📌 اینطوری مثلاً صفحه دوم رو میگیریم: آیتمهای ۱۱ تا ۲۰. --- 🧠 نکات پایانی: - همیشه قبل از Skip() مرتبسازی (OrderBy) انجام بده - برای دادههای فقط خواندنی از AsNoTracking() استفاده کن - با ToQueryString() میتونی SQL نهایی رو ببینی و بهینه کنی - انتخاب روش بارگذاری بستگی به نیاز پروژه و حجم داده داره --- 🎯 جمعبندی پادکست: با شناخت سه روش بارگذاری داده، استفاده از Select برای کم کردن حجم، و پیادهسازی صفحهبندی، میتونی پروژههای ASP.NET Core MVC رو سریعتر و بهینهتر بسازی.
پروژه ASP.Net Core MVC (وب و سی شارپ)
بهینه سازی کار با داده در ASP.Net Core MVC ساخته شده از هوش مصنوعی نکته: شاید پادکست تکراری باشد و
در EF Core وقتی از Select استفاده میکنی، میتونی هم دادههای اصلی و هم دادههای مرتبط (Navigation Properties) رو انتخاب کنی—و حتی روی همون نتیجه صفحهبندی (Skip و Take) انجام بدی.
---
🧩 ایده کلی
Select بهت اجازه میده فقط فیلدهایی که لازم داری رو از چند جدول مرتبط بگیری، بدون اینکه کل موجودیتها رو لود کنی. این کار باعث میشه حجم داده کمتر بشه و سرعت بیشتر.
---
🔹 مثال: لیست کردن همه آیتمهای مرتبط
فرض کن دو جدول داری: Product و Category (یک محصول یک دستهبندی دارد).
csharp var products = _context.Products .Select(p => new { p.Title, p.Price, CategoryName = p.Category.Name }) .ToList();📌 اینجا EF Core خودش Join میزنه و اسم دستهبندی رو هم میاره، بدون نیاز به Include(). --- 🔹 مثال: صفحهبندی روی دادههای انتخابشده
csharp int pageSize = 10; int pageNumber = 2; var products = _context.Products .Where(p => p.IsActive) .OrderBy(p => p.Title) .Select(p => new { p.Title, p.Price, CategoryName = p.Category.Name }) .Skip((pageNumber - 1) * pageSize) .Take(pageSize) .ToList();✅ این کوئری: - فقط فیلدهای لازم رو میاره (Title, Price, CategoryName) - صفحهبندی رو روی همون دادهها انجام میده - بهینهتر از Include هست وقتی کل موجودیت رو لازم نداری --- 🧠 نکات حرفهای - وقتی فقط چند فیلد لازم داری، Select بهتر از Include هست چون حجم داده کمتره - Select میتونه چند سطح رابطه رو هم بیاره، مثلاً:
csharp
.Select(o => new {
o.Id,
o.Customer.Name,
City = o.Customer.Address.City
})
- صفحهبندی (Skip/Take) رو میتونی بعد از Select یا قبلش بزنی، ولی معمولاً بعد از OrderBy و قبل از ToList() میادوقتی میخوای دادهای رو از دیتابیس بارگذاری کنی (مثلاً لیست کتابها یا محصولات)، چند مرحله مهم وجود داره که هر کد حرفهای باید رعایت کنه. این مراحل نهتنها باعث میشن کدت بهینه باشه، بلکه قابل توسعه، قابل تست و قابل فهم هم میشه.
بذار این مراحل رو خیلی واضح و قابل استفاده برات لیست کنم، طوری که همیشه بتونی بهش رجوع کنی و ترتیب اجرای کوئریها در EF Core رو اصولی یاد بگیری.
---
✅ مراحل استاندارد بارگذاری داده در EF Core
1️⃣ AsNoTracking()
- کاربرد: حذف ردیابی تغییرات توسط EF
- هدف: سبکسازی کوئریهای فقط خواندنی
- مثال:
csharp context.Books.AsNoTracking()--- 2️⃣ Where() - کاربرد: فیلتر کردن دادهها بر اساس شرط - هدف: حذف رکوردهای غیرضروری - مثال:
csharp .Where(b => b.IsAvailable == true)--- 3️⃣ جستجو (Search) - کاربرد: جستجو در متن یا فیلدهای خاص - هدف: پیدا کردن رکوردهای مرتبط با عبارت کاربر - مثال:
csharp .Where(b => b.Title.Contains(search) || b.Author.FullName.Contains(search))--- 4️⃣ OrderBy() / OrderByDescending() - کاربرد: مرتبسازی دادهها - هدف: تعیین ترتیب نمایش در لیست - مثال:
csharp .OrderBy(b => b.Title)--- 5️⃣ Skip() و Take() - کاربرد: صفحهبندی دادهها - هدف: گرفتن فقط رکوردهای صفحه فعلی - مثال:
csharp .Skip((page - 1) * pageSize).Take(pageSize)--- 6️⃣ Select() - کاربرد: انتخاب فقط فیلدهای مورد نیاز - هدف: کاهش حجم خروجی و کنترل نمایش - مثال:
csharp
.Select(b => new { b.Id, b.Title, b.IsAvailable })
---
7️⃣ ToList() یا ToListAsync()
- کاربرد: اجرای کوئری و گرفتن دادهها
- هدف: انتقال دادهها به حافظه برنامه
- مثال:
csharp .ToList()--- 8️⃣ ارسال به View - کاربرد: نمایش دادهها در Razor یا API - هدف: ارائه خروجی به کاربر - مثال:
csharp return View(books);--- 📌ترتیب استاندارد نوشتن کوئری در EF Core
csharp var query = context.TableName .AsNoTracking() // 1️⃣ سبکسازی .Where(...) // 2️⃣ فیلتر .Where(searchCondition) // 3️⃣ جستجو .OrderBy(...) // 4️⃣ مرتبسازی .Skip((page - 1) * pageSize) // 5️⃣ صفحهبندی .Take(pageSize) // 6️⃣ محدودسازی .Select(x => new { ... }) // 7️⃣ انتخاب فیلدها .ToList(); // 8️⃣ اجرا
✅ اکشن Index برای پروژه کتابخانه (نسخه آموزشی و مرحلهبهمرحله)
csharp
public IActionResult Index(int page = 1, int pageSize = 10, string search = "", string statusFilter = "", string sort = "")
{
// 1️⃣ شروع کوئری با سبکسازی
var query = _context.Books
.AsNoTracking();
// 2️⃣ فیلتر وضعیت کتاب (موجود یا فروختهشده)
if (statusFilter == "available")
query = query.Where(b => b.IsAvailable == true);
else if (statusFilter == "sold")
query = query.Where(b => b.IsAvailable == false);
// 3️⃣ جستجو در عنوان یا نام نویسنده
if (!string.IsNullOrEmpty(search))
query = query.Where(b => b.Title.Contains(search) || b.Author.FullName.Contains(search));
// 4️⃣ مرتبسازی بر اساس فیلد انتخابشده
switch (sort)
{
case "title":
query = query.OrderBy(b => b.Title);
break;
case "status":
query = query.OrderByDescending(b => b.IsAvailable);
break;
default:
query = query.OrderBy(b => b.Id); // مرتبسازی پیشفرض
break;
}
// 5️⃣ محاسبه تعداد کل رکوردها برای صفحهبندی
int totalCount = query.Count();
int totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
// 6️⃣ اعمال صفحهبندی
query = query
.Skip((page - 1) * pageSize)
.Take(pageSize);
// 7️⃣ انتخاب فیلدهای مورد نیاز
var books = query
.Select(b => new
{
b.Id,
b.Title,
b.IsAvailable,
AuthorName = b.Author.FullName
})
.ToList();
// 8️⃣ ارسال دادهها به View
ViewBag.CurrentPage = page;
ViewBag.TotalPages = totalPages;
ViewBag.TotalCount = totalCount;
ViewBag.PageSize = pageSize;
ViewBag.Search = search;
ViewBag.StatusFilter = statusFilter;
ViewBag.Sort = sort;
return View(books);
}
---
🎯 ویژگیهای این اکشن
| مرحله | توضیح |
|-------|--------|
۱ـ| AsNoTracking() | سبکسازی کوئری فقط خواندنی |
۲ـ| Where() | فیلتر وضعیت و جستجو |
۳ـ| switch | مرتبسازی بر اساس انتخاب کاربر |
۴ـ| Count() | محاسبه تعداد کل رکوردها |
۵ـ| Skip/Take | صفحهبندی واقعی |
۶ـ| Select() | خروجی سبک و قابل کنترل |
۷ـ| ViewBag | ارسال اطلاعات به View برای نمایش صفحهبندی و فیلترها
🧩 بخشهای قابل حذف یا اختیاری در اکشن Index
| بخش | کاربرد | آیا میتونی حذفش کنی؟ |
|------|--------|------------------------|
۱ـ| AsNoTracking() | سبکسازی کوئری فقط خواندنی | ✅ اگر نیاز به ویرایش نداری، بهتره باشه |
۲ـ| فیلتر statusFilter | نمایش فقط کتابهای موجود یا فروختهشده | ✅ اگر همه کتابها رو میخوای، میتونی حذفش کنی |
۳ـ| جستجو search | پیدا کردن کتاب یا نویسنده با متن واردشده | ✅ اگر صفحهات جستجو نداره، حذفش مشکلی نداره |
۴ـ| مرتبسازی sort | نمایش بر اساس عنوان یا وضعیت یا تاریخ | ✅ اگر ترتیب خاصی نمیخوای، میتونی حذفش کنی یا فقط یه OrderBy ساده بذاری |
۵ـ| صفحهبندی Skip/Take | نمایش فقط بخشی از دادهها در هر صفحه | ✅ اگر تعداد دادهها کم باشه، میتونی حذفش کنی و همه رو نشون بدی |
۶ـ| Select() | انتخاب فیلدهای مورد نیاز | ✅ اگر کل مدل رو میخوای، میتونی حذفش کنی و فقط ToList() بزنی |
۷ـ| ViewBag | ارسال دادهها به View برای نمایش فیلتر و صفحهبندی | ✅ اگر View سادهست و این اطلاعات رو نمیخوای، حذفش مشکلی نداره
---
🎯 مثال سادهشده بدون فیلتر و صفحهبندی
csharp var books = _context.Books .AsNoTracking() .OrderBy(b => b.Title) .Select(b => new { b.Id, b.Title, AuthorName = b.Author.FullName }) .ToList(); return View(books);✅ این نسخه برای لیست ساده کتابها بدون جستجو، فیلتر، یا صفحهبندی مناسبه
زمان:
حجم:
11.9M
صفر تا صد بهینه سازی کوئری در EF Core
ساخته شده از هوش مصنوعی
پروژه ASP.Net Core MVC (وب و سی شارپ)
صفر تا صد بهینه سازی کوئری در EF Core ساخته شده از هوش مصنوعی
چرا ترتیب مراحل کوئری در EF Core مهمه، باید بدونی که این ترتیب فقط برای زیبایی نیست—بلکه مستقیماً روی عملکرد، بهینهسازی، امنیت و خوانایی کد تأثیر میذاره.
بیا با هم یه پادکست آموزشی طراحی کنیم که هم شنیدنی باشه، هم کاربردی، و هم پر از مثال واقعی.
---
🎧 عنوان پادکست:
«چرا ترتیب مراحل کوئری در EF Core مهمه؟ از AsNoTracking تا ToList»
---
🎙️ امروز میخوایم دربارهی یکی از مهمترین اصول EF Core صحبت کنیم:
ترتیب نوشتن کوئریها. شاید فکر کنی ترتیب مهم نیست، ولی در واقع این ترتیب میتونه تفاوت بین یه کوئری سریع و یه کوئری کند باشه. پس با من همراه باش تا مرحلهبهمرحله بررسی کنیم.
---
🧩 مرحله 1: AsNoTracking() – سبکسازی از ابتدا
وقتی میدونی داده فقط برای نمایش هست و قرار نیست تغییرش بدی، بهتره از همون اول بگی EF Core ردیابی نکنه.
اگر بذاری آخر کوئری، EF از قبل ردیابی کرده و دیگه فایدهای نداره.
📌 پس باید اول بیاد تا کل کوئری سبک بشه.
---
🧩 مرحله 2 و 3: Where() و جستجو – حذف دادههای اضافی قبل از هر چیز
اگه اول Include یا Select بزنی و بعد Where، ممکنه کلی داده بیاد که اصلاً لازم نداری.
مثل اینه که اول همه کتابها رو بیاری، بعد بگی فقط اونایی که موجودن رو نگه دار.
📌 پس اول فیلتر کن، بعد ادامه بده.
---
🧩 مرحله 4: OrderBy() – مرتبسازی قبل از صفحهبندی
اگه قبل از Skip مرتبسازی نکنی، صفحهبندی بیمعنی میشه. چون ترتیب مشخص نیست و هر بار دادهها جابهجا میشن.
📌 پس اول مرتب کن، بعد صفحهبندی کن.
---
🧩 مرحله 5 و 6: Skip() و Take() – کنترل حجم داده
اینجا مشخص میکنی چند رکورد رد بشه و چند تا گرفته بشه.
اگه اینو بعد از ToList() بزنی، کل دادهها لود میشن و فقط در حافظه فیلتر میشن—که خیلی سنگینه.
📌 پس قبل از ToList() باید باشه تا در سطح دیتابیس اجرا بشه.
---
🧩 مرحله 7: Select() – فقط فیلدهای لازم
اگه کل موجودیت رو بیاری (Product یا Book) ولی فقط Title و Price رو لازم داشته باشی، داری حافظه رو بیخود پر میکنی.
با Select فقط اون چیزی که لازم داری رو میگیری.
📌 بهتره بعد از فیلتر و صفحهبندی باشه، چون روی دادههای نهایی اعمال میشه.
---
🧩 مرحله 8: ToList() – اجرای نهایی
تا اینجا فقط کوئری ساخته شده. با ToList() یا ToListAsync() کوئری اجرا میشه و دادهها وارد حافظه میشن.
اگه زودتر بزنی، همه چیز در حافظه انجام میشه و بهینه نیست.
📌 پس همیشه آخر باشه.
---
🎯 جمعبندی پادکست
ترتیب مراحل کوئری در EF Core فقط یه توصیه نیست—یه اصل مهمه برای:
- بهینهسازی عملکرد
- کاهش مصرف حافظه
- جلوگیری از بارگذاری غیرضروری
- افزایش خوانایی و تستپذیری کد
✅ کوئری کامل و بهینه برای پروژه کتابخانه با همه ویژگیهایی که گفتی
csharp var query = _context.Books .AsNoTracking() // 1️⃣ سبکسازی کوئری فقط خواندنی // 2️⃣ فیلتر وضعیت کتاب (موجود یا فروختهشده) .Where(b => statusFilter == "available" ? b.IsAvailable : statusFilter == "sold" ? !b.IsAvailable : true) // 3️⃣ جستجو در عنوان کتاب یا نام نویسنده .Where(b => string.IsNullOrEmpty(search) || b.Title.Contains(search) || b.Author.FullName.Contains(search)) // 4️⃣ مرتبسازی بر اساس تاریخ ثبت (جدیدترین یا قدیمیترین) .OrderByDescending(b => sort == "new" ? b.Id : 0) .ThenBy(b => sort == "old" ? b.Id : 0) // 5️⃣ صفحهبندی بر اساس تعداد کل رکوردها و صفحه فعلی .Skip((page - 1) * pageSize) .Take(pageSize) // 6️⃣ انتخاب فیلدهای مورد نیاز برای نمایش .Select(b => new { b.Id, b.Title, b.IsAvailable, AuthorName = b.Author.FullName }) // 7️⃣ اجرای کوئری و گرفتن دادهها .ToList();🔍 تفاوتهای اصلی بین دو روش | تفاوت | روش اول (if و switch) | روش دوم (شرط داخل Where و OrderBy) | |-------|-----------------------------|----------------------------------------| | سبک نوشتن | مرحلهمرحله با شرطهای جدا | همهچیز در یک زنجیرهی متصل | | خوانایی | ✅ واضحتر برای مبتدیها | کمی فشردهتر ولی حرفهایتر | | انعطافپذیری | راحتتر برای شرطهای پیچیده | مناسب برای کوئریهای ساده و مستقیم | | قابل تست بودن | میتونی هر مرحله رو جدا تست بزنی | سختتر برای دیباگ مرحلهای | | کنترل منطق | شرطها جدا و قابل تغییر | شرطها داخل کوئری، کمتر قابل تغییر در لحظه | | مناسب برای پروژههای بزرگ | ✅ بهتر برای منطق پیچیده | مناسب برای لیستهای سبک و سریع | | تعداد متغیرها | از query چند بار استفاده میشه | فقط یک بار تعریف و استفاده میشه |