پروژه ASP.Net Core MVC (وب و سی شارپ)
مدلها، روابط و Include رازهای مدیریت داده در ASP.Net Core MVC ساخته شده از هوش مصنوعی
در این قسمت از پادکست، میخوایم دربارهی یکی از مفاهیم مهم در طراحی دیتابیس و کار با Entity Framework Core در پروژههای ASP.NET Core MVC صحبت کنیم:
مدلها، ارتباط بین جدولها، و استفاده از Include برای بارگذاری دادههای مرتبط.
اگه تا حالا با دادههای مرتبط مثل کاربران و سفارشها یا دستهبندیها و محصولات کار کردی، این قسمت برایت مثل نقشهی راهه.
---
🎙️ بخش اول: مدل یعنی چی؟
در ASP.NET Core MVC، Model نمایندهی یک جدول در دیتابیسه.
هر کلاس مدل شامل خصوصیاتیه که به ستونهای جدول تبدیل میشن، و میتونه با مدلهای دیگه هم ارتباط داشته باشه.
🔸 مثال ساده:
csharp
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
csharp
public class Product
{
public int Id { get; set; }
public string Title { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
اینجا هر محصول به یه دستهبندی تعلق داره—یعنی ارتباط یکبهچند (One-to-Many) بین جدولها.
---
🎙️ بخش دوم: انواع ارتباط بین جدولها
🔗 یک به یک (One-to-One):
مثلاً هر کاربر یک پروفایل دارد.
🔗 یک به چند (One-to-Many):
مثلاً هر دستهبندی چند محصول دارد.
🔗 چند به چند (Many-to-Many):
مثلاً هر دانشآموز در چند کلاس شرکت میکند و هر کلاس چند دانشآموز دارد.
در EF Core، این ارتباطها با استفاده از Navigation Properties و کلیدهای خارجی (Foreign Keys) تعریف میشن.
---
🎙️ بخش سوم: استفاده از Include — بارگذاری دادههای مرتبط
وقتی میخوای دادههای مرتبط رو از دیتابیس بخونی، باید از Include استفاده کنی تا EF Core اونها رو همراه با داده اصلی بارگذاری کنه.
🔧 مثال:
csharp
var categories = _context.Categories
.Include(c => c.Products)
.ToList();
اینجا EF Core هم دستهبندیها رو میاره، هم لیست محصولات مربوط به هر دستهبندی رو.
🔸 مزایا:
- کاهش تعداد کوئریها
- دسترسی مستقیم به دادههای مرتبط
- بهینهسازی عملکرد در نمایش لیستها یا جزئیات
---
🎯 نتیجهگیری
مدلها پایهی ارتباط با دیتابیس هستن، ارتباط بین جدولها ساختار پروژه رو مشخص میکنه، و Include ابزار قدرتمندی برای بارگذاری دادههای مرتبطه.
اگه این سه رو خوب درک کنی، میتونی پروژههایی بسازی که هم تمیز باشن، هم سریع، هم قابل توسعه.
پروژه ASP.Net Core MVC (وب و سی شارپ)
مدلها، روابط و Include رازهای مدیریت داده در ASP.Net Core MVC ساخته شده از هوش مصنوعی
در این قسمت از پادکست، میخوایم دربارهی یکی از موضوعات مهم در کار با Entity Framework Core در پروژههای ASP.NET Core MVC صحبت کنیم:
زنجیر کردن Include، بارگذاری دادههای مرتبط، کنترل حجم اطلاعات، و بهینهسازی خواندن دادهها.
این موضوع برای پروژههایی که دادههای پیچیده و حجیم دارن، حیاتی و تعیینکنندهست.
---
🎙️ بخش اول: زنجیر کردن Include — بارگذاری چندلایهای
وقتی مدلهات ارتباط تو در تو دارن، مثل:
- دستهبندی → محصول → سفارش
میخوای همهی این دادهها رو با یه کوئری بخونی. اینجاست که زنجیر کردن Include وارد میشه:
csharp
var categories = _context.Categories
.Include(c => c.Products)
.ThenInclude(p => p.Orders)
.ToList();
🔸 این یعنی:
اول دستهبندیها، بعد محصولات هر دسته، بعد سفارشهای هر محصول—همه در یک کوئری.
---
🎙️ بخش دوم: بارگذاری از قبل (Eager Loading)
وقتی مطمئنی که به دادههای مرتبط نیاز داری، بهتره از Eager Loading استفاده کنی تا همهچیز همزمان بارگذاری بشه.
مزایا:
- فقط یک کوئری اجرا میشه
- سرعت بالا در نمایش اولیه
- مناسب برای صفحات فقط خواندنی
اما مراقب باش: اگه دادهها حجیم باشن و همهشون رو نخوای، باعث مصرف زیاد حافظه و کندی میشه.
---
🎙️ بخش سوم: بدهبستان در بارگذاری دادههای حجیم
🔄 همیشه باید بین دو چیز تعادل برقرار کنی:
| گزینه | مزایا | معایب |
|-------|--------|--------|
| Eager Loading | سرعت بالا، کوئری واحد | بارگذاری دادههای اضافی
| Lazy Loading | سبکتر، فقط در صورت نیاز | کوئریهای متعدد، کندی در حجم بالا
| Explicit Loading | کنترل کامل | نیاز به کدنویسی بیشتر
> پس اگه دادههات حجیمه ولی فقط گاهی بهشون نیاز داری، بهتره از Explicit Loading استفاده کنی تا فقط وقتی لازم شد، اونها رو بارگذاری کنی.
---
🎙️ بخش چهارم: کنترل دادههای فقط خواندنی
وقتی دادهها فقط برای نمایش هستن و قرار نیست تغییر کنن، میتونی از AsNoTracking() استفاده کنی:
csharp
var products = _context.Products
.AsNoTracking()
.Include(p => p.Category)
.ToList();
🔸 مزایا:
- کاهش مصرف حافظه
- افزایش سرعت
- مناسب برای صفحات گزارش، لیستها، داشبوردها
---
🎯 نتیجهگیری
زنجیر کردن Include، انتخاب نوع بارگذاری، و استفاده از AsNoTracking() ابزارهایی هستن که بهت کمک میکنن دادههای مرتبط رو هوشمندانه، سریع و بهینه بارگذاری کنی—بدون اینکه پروژهت سنگین یا کند بشه.
برای اینکه بتونی با EF Core و Include() دادههای مرتبط رو بارگذاری کنی و همزمان صفحهبندی (pagination) انجام بدی—مثلاً ۱۰ تا اول در صفحه ۱، ۱۰ تای بعدی در صفحه ۲ و...—باید از ترکیب Skip() و Take() استفاده کنی.
---
🧠 ساختار کلی صفحهبندی همراه با Include
فرض کن میخوای لیست محصولات رو همراه با دستهبندیشون نمایش بدی، ۱۰ تا در هر صفحه:
csharp int pageSize = 10; int pageNumber = 2; // یعنی صفحه دوم var products = _context.Products .AsNoTracking() .Include(p => p.Category) // بارگذاری دستهبندی مرتبط .Where(p => p.IsActive) // فیلتر .OrderBy(p => p.Title) // مرتبسازی .Skip((pageNumber - 1) * pageSize) // رد کردن صفحات قبلی .Take(pageSize) // گرفتن تعداد مشخص .ToList();--- 🔍 توضیح خطبهخط: - Include(p => p.Category) → بارگذاری دادههای مرتبط - Where(...) → فیلتر کردن دادهها - OrderBy(...) → مرتبسازی برای حفظ ترتیب - Skip(...) → رد کردن تعداد مشخص از رکوردها - Take(...) → گرفتن تعداد مشخص برای هر صفحه - AsNoTracking() → فقط خواندنی، سریعتر و سبکتر --- 📋 نکتههای حرفهای: - همیشه قبل از Skip() باید OrderBy() بزنی، چون بدون ترتیب، صفحهبندی معنی نداره - میتونی کوئری رو با ToQueryString() چاپ کنی تا SQL نهایی رو ببینی:
csharp Console.WriteLine(productsQuery.ToQueryString());- برای صفحهبندی بهتر، میتونی از کتابخانههایی مثل X.PagedList یا Sieve هم استفاده کنی
معمولاً مقدار شماره صفحه (page number) از طریق متد GET و QueryString از سمت مرورگر یا کاربر ارسال میشه. یعنی وقتی کاربر روی دکمهی «صفحه بعد» یا «صفحه ۳» کلیک میکنه، شماره صفحه بهصورت پارامتر در URL ارسال میشه.
---
🧩 مثال از URL با شماره صفحه:
https://example.com/Products?page=2🔸 اینجا page=2 یعنی کاربر درخواست داده که صفحه دوم رو ببینه. --- 🔧 دریافت مقدار صفحه در کنترلر ASP.NET Core MVC در کنترلر، میتونی مقدار page رو از QueryString بگیری:
csharp
public IActionResult Index(int page = 1)
{
int pageSize = 10;
int skipCount = (page - 1) * pageSize;
var products = _context.Products
.AsNoTracking()
.Include(p => p.Category)
.OrderBy(p => p.Title)
.Skip(skipCount)
.Take(pageSize)
.ToList();
return View(products);
}
🔹 اگر کاربر هیچ شماره صفحهای نفرسته، مقدار پیشفرض page = 1 در نظر گرفته میشه.
---
📋 در View چطور لینک صفحهها رو بسازی؟
html @for (int i = 1; i <= Model.TotalPages; i++) { <a href="?page=@i">@i</a> }🔸 این لینکها باعث میشن شماره صفحه بهصورت GET ارسال بشه و کنترلر اون رو دریافت کنه. --- ✅ نتیجهگیری - مقدار صفحه معمولاً از طریق QueryString و متد GET ارسال میشه - در کنترلر با پارامتر int page دریافت میشه - با استفاده از Skip() و Take()، دادههای مربوط به اون صفحه بارگذاری میشن
LabNobat.zip
حجم:
25.2M
معرفی آموزشی پروژه EFCoreDemo
یک سیستم ساده مدیریت نوبت آزمایشگاه
پروژه ASP.Net Core MVC (وب و سی شارپ)
معرفی آموزشی پروژه EFCoreDemo یک سیستم ساده مدیریت نوبت آزمایشگاه
📌 این پروژه چه کار میکند؟
پروژه EFCoreDemo یک سیستم نمونه برای مدیریت نوبتهای آزمایشگاه است که با ASP.NET Core MVC و Entity Framework Core ساخته شده و امکانات زیر را دارد:
1. مدیریت نوبتها (Appointments)
• ثبت نوبت جدید با انتخاب بیمار و خدمت
• نمایش لیست نوبتها
• ویرایش و حذف نوبتها
• نمایش جزئیات هر نوبت
2. مدیریت بیماران (Patients)
• ثبت، ویرایش، حذف و مشاهده اطلاعات بیماران
3. مدیریت خدمات آزمایشگاهی (Lab Services)
• ثبت، ویرایش، حذف و مشاهده خدمات
4. جستجو و فیلتر
• جستجو بر اساس نام بیمار یا عنوان خدمت
• فیلتر بر اساس وضعیت نوبت (ثبتشده، لغو شده، انجام شده)
• فیلتر بر اساس تاریخ خاص
5. مرتبسازی هوشمند
• جدیدترین یا قدیمیترین
• مرتبسازی ترکیبی نام بیمار (فارسی + انگلیسی)
• مرتبسازی بر اساس عنوان خدمت
6. صفحهبندی (Paging)
• نمایش دادهها بهصورت صفحهبهصفحه با امکان تعیین تعداد رکوردها
7. داشبورد اصلی
• نمایش آمار کلی (تعداد بیماران، خدمات، نوبتهای امروز، نوبتهای لغو شده)
• نمایش ۵ نوبت آخر با دکمه «اطلاعات بیشتر»
8. اعتبارسنجی فرمها
• بررسی ورودیها با پیامهای فارسی
• اعتبارسنجی تاریخ و جلوگیری از ورود تاریخ نامعتبر
9. سه روش بارگذاری دادهها
• Eager Loading
برای بارگذاری همزمان دادههای مرتبط
• Lazy Loading
برای بارگذاری خودکار هنگام دسترسی
• Explicit Loading
برای بارگذاری دستی در زمان دلخواه
🎯 این پروژه چه چیزهایی برای آموزش دارد؟
این پروژه یک منبع عالی برای یادگیری عملی مفاهیم زیر است:
• معماری MVC در ASP.NET Core
• Entity Framework Core
و نحوه اتصال به دیتابیس
• ساخت مدلها و روابط (One-to-Many, Many-to-Many)
• Migrations
برای ایجاد و تغییر ساختار دیتابیس
• عملیات CRUD کامل
• LINQ
برای جستجو، فیلتر و مرتبسازی
• اعتبارسنجی سمت سرور و کلاینت
• مدیریت ViewBag و ViewData برای ارسال داده به ویو
• طراحی فرمها و جدولها با Bootstrap 5
• صفحهبندی و مرتبسازی ترکیبی
• کار با تاریخ و فرمتبندی آن
• بهینهسازی کوئریها با انتخاب روش مناسب بارگذاری دادهها (Eager, Lazy, Explicit)
در پروژههای EFCoreDemo، بارگذاری دادههای مرتبط یکی از مهمترین مفاهیمه. حالا بیایم سه روش اصلی بارگذاری دادهها در EF Core رو دقیق، آموزشی و با مثال بررسی کنیم تا تفاوتهاشون کاملاً روشن بشه.
---
🔍 ۱. Eager Loading (بارگذاری پیشدستانه)
✅ تعریف:
دادههای مرتبط همزمان با موجودیت اصلی از دیتابیس گرفته میشن. یعنی همه چیز با یک کوئری SQL بارگذاری میشه.
✅ کاربرد:
وقتی مطمئنی که دادههای مرتبط رو لازم داری و نمیخوای چند کوئری جداگانه اجرا بشه.
✅ مثال در EFCoreDemo:
csharp var appointments = _context.Appointments .Include(a => a.Patient) .Include(a => a.LabService) .ToList();📌 اینجا EF Core یک کوئری SQL میسازه که اطلاعات نوبت، بیمار و خدمت رو همزمان میگیره. --- 🟣 ۲. Lazy Loading (بارگذاری تنبل) ✅ تعریف: دادههای مرتبط فقط زمانی از دیتابیس گرفته میشن که به آنها دسترسی پیدا کنی. یعنی تا وقتی appointment.Patient.FullName رو نخونی، EF Core کوئری اجرا نمیکنه. ✅ پیشنیازها: - نصب پکیج Microsoft.EntityFrameworkCore.Proxies - فعالسازی در DbContext:
csharp optionsBuilder.UseLazyLoadingProxies();- virtual بودن Navigation Propertyها:
csharp
public virtual Patient Patient { get; set; }
✅ مثال در EFCoreDemo:
csharp var appointment = _context.Appointments.First(); var patientName = appointment.Patient.FullName; // کوئری جداگانه اینجا اجرا میشه📌 ظاهر کد سادهست، ولی پشتصحنه EF Core کوئری جداگانه برای Patient اجرا میکنه. --- 🔵 ۳. Explicit Loading (بارگذاری صریح) ✅ تعریف: دادههای مرتبط فقط زمانی بارگذاری میشن که خودت بهصورت دستی دستور بدی. مناسب برای کنترل دقیق و جلوگیری از بارگذاری اضافی. ✅ مثال در EFCoreDemo:
csharp var appointment = await _context.Appointments.FirstAsync(); await _context.Entry(appointment).Reference(a => a.Patient).LoadAsync(); await _context.Entry(appointment).Reference(a => a.LabService).LoadAsync();📌 اینجا EF Core هیچ داده مرتبطی رو خودش نمیگیره، مگر اینکه با .LoadAsync() صریحاً دستور بدی. --- 🎯 تفاوت سه روش بارگذاری دادهها در EF Core 🟢 Eager Loading — بارگذاری پیشدستانه وقتی از ابتدا میدونی که به دادههای مرتبط نیاز داری، این روش بهترین انتخابه. EF Core با استفاده از .Include() همه اطلاعات مرتبط رو در یک کوئری SQL میگیره. 🔸 مزیت: سریع و بدون کوئری اضافه 🔸 کنترل: کم، چون همه چیز از اول بارگذاری میشه 🔸 مناسب برای: نمایش لیستها یا داشبوردهایی که اطلاعات کامل لازم دارن --- 🔵 Lazy Loading — بارگذاری تنبل در این روش، EF Core فقط زمانی دادههای مرتبط رو بارگذاری میکنه که به اونها دست بزنی. یعنی وقتی مثلاً appointment.Patient.FullName رو بخونی، تازه کوئری اجرا میشه. 🔸 مزیت: سبکتر در ابتدا، ولی ممکنه کوئریهای زیادی اجرا بشه 🔸 کنترل: متوسط، چون بارگذاری خودکار انجام میشه 🔸 مناسب برای: فرمهایی که فقط گاهی به دادههای مرتبط نیاز دارن --- 🟣 Explicit Loading — بارگذاری صریح اینجا همه چیز تحت کنترل توئه. EF Core هیچ دادهای رو خودش بارگذاری نمیکنه مگر اینکه صریحاً دستور بدی. با استفاده از .Load() یا .LoadAsync() میتونی دقیقاً مشخص کنی چه چیزی و کی بارگذاری بشه. 🔸 مزیت: کنترل کامل روی کوئریها 🔸 کنترل: زیاد، چون همه چیز دستی انجام میشه 🔸 مناسب برای: سناریوهایی که بهینهسازی کوئریها مهمه یا دادههای مرتبط فقط در شرایط خاص لازم هستن --- 🔧 نکته مهم در EFCoreDemo در ظاهر، کدهای Lazy و Explicit ممکنه شبیه هم باشن چون هر دو بعد از گرفتن موجودیت اصلی، دادههای مرتبط رو جداگانه میگیرن. اما تفاوت اصلی اینه که: - Lazy خودش کوئری اجرا میکنه وقتی به داده دست بزنی - Explicit فقط وقتی خودت .Load() بزنی کوئری اجرا میشه یعنی Lazy مخفیانه عمل میکنه، ولی Explicit کاملاً تحت کنترل توئه.
بذار دقیق و آموزشی برات توضیح بدم که آیا استفاده از .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 و ساختار آموزشی پروژه