پروژه ASP.Net Core MVC (وب و سی شارپ)
پیکربندی پایگاه داده در EF Core از DBContext تا Fluent API ساخته شده از هوش مصنوعی
بیا با هم یه پادکست آموزشی طراحی کنیم دربارهی کانتکس، مدلبیلدر و مدلکریتینگ در EF Core و ASP.NET Core MVC. این پادکست میتونه هم برای یادگیری خودت مفید باشه، هم برای تولید محتوا در کانالت.
---
🎧 عنوان پادکست:
«در دل DbContext: مدلسازی حرفهای با ModelBuilder و OnModelCreating در ASP.NET Core MVC»
---
🎙️ مقدمه
سلام! امروز میخوایم بریم سراغ قلب ارتباط با دیتابیس در ASP.NET Core MVC—یعنی کلاس DbContext.
با هم بررسی میکنیم که چطور با ModelBuilder و متد OnModelCreating میتونیم ساختار دیتابیس رو دقیق، حرفهای و قابل توسعه طراحی کنیم.
---
🧩 بخش اول: DbContext چیست؟
- کلاس مرکزی برای ارتباط با دیتابیس
- شامل DbSetها برای هر مدل (مثل Books, Users, Orders)
- EF Core از این کلاس برای ساخت کوئری، ذخیرهسازی و بارگذاری داده استفاده میکنه
---
🔹 بخش دوم: OnModelCreating و ModelBuilder
✅ OnModelCreating
- متدی در DbContext که EF Core هنگام راهاندازی صدا میزنه
- داخلش میتونی ساختار جدولها، روابط، محدودیتها و رفتارها رو تعریف کنی
✅ ModelBuilder
- شیء ورودی به OnModelCreating
- باهاش میتونی مدلها رو پیکربندی کنی با Fluent API
---
🔧 بخش سوم: چه کارهایی میتونیم با ModelBuilder انجام بدیم؟
1️⃣ تعریف کلید اصلی و ترکیبی
csharp
modelBuilder.Entity<Book>().HasKey(b => b.Id);
2️⃣ تعریف روابط بین جدولها
csharp
modelBuilder.Entity<Book>()
.HasOne(b => b.Author)
.WithMany(a => a.Books)
.HasForeignKey(b => b.AuthorId);
3️⃣ جلوگیری از حذف آیتمهای مرتبط
csharp
.OnDelete(DeleteBehavior.Restrict);
4️⃣ محدودیت روی فیلدها
csharp
.Property(b => b.Title).HasMaxLength(200).IsRequired();
5️⃣ مقدار پیشفرض
csharp
.Property(b => b.IsAvailable).HasDefaultValue(true);
6️⃣ فیلتر جهانی
csharp
.HasQueryFilter(p => p.IsActive);
---
📋 بخش چهارم: آیا ModelBuilder و OnModelCreating جدا هستند؟
- ModelBuilder فقط داخل OnModelCreating استفاده میشه
- OnModelCreating متدی مستقل در DbContext هست
- میتونی پیکربندیها رو به کلاسهای جداگانه منتقل کنی با ApplyConfiguration() برای نظم بیشتر
---
🎯 جمعبندی پادکست
با استفاده از ModelBuilder در OnModelCreating میتونی:
- ساختار دیتابیس رو دقیق کنترل کنی
- روابط بین جدولها رو تعریف کنی
- از حذف ناخواسته دادههای مرتبط جلوگیری کنی
- محدودیتها، ایندکسها و فیلترهای پیشفرض رو تنظیم کنی
- پروژهت رو حرفهای، امن و قابل توسعه بسازی
همش این نیست—دنیای EF Core و ASP.NET Core MVC خیلی گستردهتره! 😄
اون چیزی که تا حالا گفتیم مربوط به پیکربندی مدلها با ModelBuilder و OnModelCreating بود، ولی کلی قابلیت دیگه هم وجود داره که مکمل این بخشها هستن و پروژهت رو حرفهایتر میکنن.
---
🧩 چیزهای دیگر که کنار ModelBuilder و OnModelCreating وجود دارند:
🔹 ۱. Data Annotations
پیکربندی مدلها با استفاده از ویژگیهای تزئینی روی کلاسها:
csharp
[Required]
[MaxLength(100)]
public string Title { get; set; }
📌 سادهتر از Fluent API، ولی محدودتر
---
🔹 ۲. Migration و بهروزرسانی دیتابیس
- ایجاد فایلهای مهاجرت با Add-Migration
- اعمال تغییرات با Update-Database
- بررسی تاریخچه تغییرات دیتابیس
📌 برای هماهنگی مدلها با دیتابیس واقعی
---
🔹 ۳. Seed Data (داده اولیه)
csharp
modelBuilder.Entity<Category>().HasData(
new Category { Id = 1, Name = "ASP.NET" },
new Category { Id = 2, Name = "EF Core" }
);
📌 برای پر کردن دیتابیس با دادههای پیشفرض
---
🔹 ۴. Global Query Filters
csharp
modelBuilder.Entity<Product>()
.HasQueryFilter(p => p.IsActive);
📌 اعمال فیلتر روی همهی کوئریها بهصورت خودکار
---
🔹 ۵. Value Conversions
تبدیل نوع دادهها هنگام ذخیرهسازی:
csharp
modelBuilder.Entity<User>()
.Property(u => u.IsAdmin)
.HasConversion<int>();
📌 برای تبدیل bool به int یا enum به string
---
🔹 ۶. Shadow Properties
فیلدهایی که در کلاس مدل نیستن ولی در دیتابیس هستن:
csharp
modelBuilder.Entity<Product>()
.Property<DateTime>("LastUpdated");
📌 برای ذخیره اطلاعات سیستمی بدون تغییر مدل
---
🔹 ۷. Table Splitting
ذخیره چند کلاس در یک جدول:
csharp
modelBuilder.Entity<Order>().ToTable("Orders");
modelBuilder.Entity<Invoice>().ToTable("Orders");
📌 برای بهینهسازی ساختار دیتابیس
---
🔹 ۸. Query Types / Keyless Entities
برای نمایش دادههایی که کلید اصلی ندارن:
csharp
modelBuilder.Entity<ReportView>().HasNoKey();
📌 مناسب برای گزارشها و ویوهای فقطخواندنی
---
🔹 ۹. Change Tracking و State Management
بررسی وضعیت رکوردها:
csharp
context.Entry(book).State = EntityState.Modified;
📌 برای کنترل دقیق عملیات CRUD
---
🔹 ۱۰. Interceptors و Logging
شنود عملیات EF Core:
csharp
optionsBuilder.AddInterceptors(new MyInterceptor());
📌 برای لاگگیری، امنیت، یا مانیتورینگ
---
🎯 نتیجهگیری
پس ModelBuilder و OnModelCreating فقط بخشی از دنیای EF Core هستن.
کنار اونها کلی ابزار و تکنیک دیگه وجود داره که بهت کمک میکنن:
- ساخت دیتابیس حرفهای
- کنترل رفتار دادهها
- بهینهسازی عملکرد
- تولید گزارش و داشبورد
- و حتی امنیت و لاگگیری
---
پروژه ASP.Net Core MVC (وب و سی شارپ)
🎯 درس جدید: تنظیم دقیق مدلها با ModelBuilder در EF Core در این مرحله از پروژه مدیریت نویسنده و کتا
پاسخ بستگی داره که هدفت چی باشه—آیا فقط میخوای بررسی کنی که نویسنده کتاب دارد یا نه؟ یا میخوای اطلاعات کامل نویسنده و کتابها را واکشی کنی؟ بیایم دقیق مقایسه کنیم:
---
✅ روش اول: واکشی فقط نام اولین کتاب
csharp var firstTitle = _context.Books .Where(b => b.AuthorId == id) .Select(b => b.Title) .FirstOrDefault();🔹 هدف: فقط گرفتن نام اولین کتاب 🔹 مزایا: - سریعتر و سبکتر - فقط یک ستون (Title) واکشی میشود - مناسب برای بررسی ساده یا نمایش خلاصه 🔹 معایب: - اطلاعات نویسنده واکشی نمیشود - اگر بخواهی لیست کامل کتابها یا جزئیات بیشتر داشته باشی، کافی نیست --- ✅ روش دوم: واکشی نویسنده با لیست کتابها
csharp var author = _context.Authors .Include(a => a.Books) .FirstOrDefault(a => a.Id == id);🔹 هدف: گرفتن نویسنده و تمام کتابهایش 🔹 مزایا: - اطلاعات کامل نویسنده و کتابها در دسترس است - مناسب برای Viewهایی که جزئیات کامل را نمایش میدهند - میتوانی بررسی کنی author.Books.Any() یا لیست را نمایش دهی 🔹 معایب: - سنگینتر از روش اول - در دیتابیسهای بزرگ ممکن است کندتر باشد --- ✨ نتیجهگیری برای دفترت | هدف | روش بهتر | دلیل | |------|-----------|--------| | فقط بررسی یا نمایش یک کتاب | firstTitle | سبک و سریع | | نمایش نویسنده و همه کتابها | author + Include | کامل و دقیق | | پروژههای بزرگ با داده زیاد | firstTitle | بهینهتر | | فرمهای جزئیات یا حذف | author + Include | چون نیاز به بررسی Books.Any() داری |
پروژه ASP.Net Core MVC (وب و سی شارپ)
🎯 درس جدید: تنظیم دقیق مدلها با ModelBuilder در EF Core در این مرحله از پروژه مدیریت نویسنده و کتا
اگر بخوای همون دادهها رو با Select بنویسی، یعنی بهجای واکشی کامل شیء Author، فقط فیلدهای خاصی رو واکشی کنی—و این باعث میشه کد سبکتر و سریعتر بشه، مخصوصاً در دیتابیسهای بزرگ.
---
✅ تبدیل Include + FirstOrDefault به Select
کد اصلی:
csharp var author = _context.Authors .Include(a => a.Books) .FirstOrDefault(a => a.Id == id);🔹 این کد کل شیء Author و لیست Books رو واکشی میکنه 🔹 اگر فقط بعضی فیلدها رو بخوای، میتونی از Select استفاده کنی: --- 🎯 نسخه با Select
csharp var authorData = _context.Authors .Where(a => a.Id == id) .Select(a => new { a.Id, a.FullName, BookTitles = a.Books.Select(b => b.Title).ToList() }) .FirstOrDefault();🔹 این کد فقط Id, FullName و لیست Title کتابها رو واکشی میکنه 🔹 خروجی یک شیء بینام (anonymous type) هست—not کلاس Author --- 🧠 تفاوتها | مورد | Include + FirstOrDefault | Select + FirstOrDefault | |------|-----------------------------|----------------------------| | نوع خروجی | Author | شیء بینام | | حجم داده | زیادتر | سبکتر | | انعطاف در انتخاب فیلدها | کم | زیاد | | مناسب برای View | بله | بله، اگر فقط فیلدهای خاص بخواهی | | مناسب برای حذف یا ویرایش | بهتر است از Author استفاده شود | چون نیاز به شیء کامل داری | --- ✨ نتیجهگیری برای دفترت | هدف | روش بهتر | دلیل | |------|-----------|--------| | نمایش خلاصه اطلاعات | Select | سبکتر و سریعتر | | عملیات حذف یا ویرایش | Include + FirstOrDefault | نیاز به شیء کامل | | واکشی فقط نام کتابها | Select(a => new { ... }) | دقیق و بهینه |
پروژه ASP.Net Core MVC (وب و سی شارپ)
🎯 درس جدید: تنظیم دقیق مدلها با ModelBuilder در EF Core در این مرحله از پروژه مدیریت نویسنده و کتا
var firstTitle = _context.Books
.Where(b => b.AuthorId == id)
.Select(b => b.Title)
.FirstOrDefault();
دقیقاً همین کد بهدرستی کار میکند برای اینکه بفهمی آیا نویسنده کتاب دارد یا نه 👌
بیایم دقیق بررسی کنیم که چرا این روش مؤثر و بهینه است:
---
✅ کد بررسی داشتن کتاب با FirstOrDefault
csharp var firstTitle = _context.Books .Where(b => b.AuthorId == id) .Select(b => b.Title) .FirstOrDefault();🔹 این کد میره سراغ جدول Books 🔹 فقط کتابهایی رو بررسی میکنه که AuthorId برابر با id باشه 🔹 فقط ستون Title رو واکشی میکنه—not کل شیء کتاب 🔹 فقط اولین عنوان کتاب رو میگیره، یا null اگر هیچ کتابی نباشه --- 🎯 بررسی شرط
csharp
if (firstTitle != null)
{
// نویسنده کتاب دارد
}
else
{
// نویسنده کتاب ندارد
}
✅ این شرط کاملاً درست و سبک هست
✅ مناسب برای پروژههایی که فقط میخوای بررسی کنی نویسنده کتاب دارد یا نه
✅ سریعتر از Include و واکشی کل لیست کتابها
---
✨ مزایای این روش
| مزیت | توضیح |
|------|-------|
| سبک و سریع | فقط یک مقدار واکشی میشود—not کل لیست |
| بدون نیاز به Include | چون فقط از جدول Books استفاده میکنی |
| مناسب برای شرط حذف | چون فقط بررسی میکنی که کتاب دارد یا نه |
| قابل استفاده در پروژههای بزرگ | چون فشار کمتری به دیتابیس وارد میکند
پروژه ASP.Net Core MVC (وب و سی شارپ)
🎯 درس جدید: تنظیم دقیق مدلها با ModelBuilder در EF Core در این مرحله از پروژه مدیریت نویسنده و کتا
وقتی از ModelBuilder استفاده میکنی تا محدودیتهایی مثل ایندکس یکتا برای کتاب تکراری یا ممنوعیت حذف نویسنده دارای کتاب تعریف کنی، اگر کاربر خلاف این محدودیتها عمل کنه، خطای SQL یا EF Core رخ میده. حالا باید در اکشنهای کنترلر، این خطاها رو مدیریت (catch) کنی تا برنامه کرش نکنه و پیام مناسب به کاربر نمایش داده بشه.
---
✅ 1. جلوگیری از ثبت کتاب تکراری با مدیریت خطای SQL
📍 فرض: در ModelBuilder نوشتی:
csharp modelBuilder.Entity<Book>() .HasIndex(b => new { b.Title, b.AuthorId }) .IsUnique();📍 حالا در اکشن Create یا Edit باید خطای دیتابیس رو مدیریت کنی:
csharp
try
{
_context.Books.Add(book);
_context.SaveChanges();
return RedirectToAction("Index");
}
catch (DbUpdateException ex)
{
// بررسی اینکه خطا مربوط به ایندکس یکتا بوده
if (ex.InnerException?.Message.Contains("IXBooksTitle_AuthorId") == true)
{
ModelState.AddModelError("Title", "این نویسنده قبلاً کتابی با این عنوان دارد.");
}
else
{
ModelState.AddModelError("", "خطایی در ثبت کتاب رخ داد.");
}
return View(book);
}
🔹 این کد خطای DbUpdateException رو مدیریت میکنه
🔹 اگر خطا مربوط به ایندکس یکتا باشه، پیام مناسب نمایش داده میشه
🔹 اگر خطای دیگری باشه، پیام عمومی نمایش داده میشه
---
✅ 2. جلوگیری از حذف نویسنده دارای کتاب با مدیریت خطای SQL
📍 فرض: در ModelBuilder نوشتی:
csharp modelBuilder.Entity<Book>() .HasOne(b => b.Author) .WithMany(a => a.Books) .HasForeignKey(b => b.AuthorId) .OnDelete(DeleteBehavior.Restrict);📍 حالا در اکشن DeleteConfirmed باید خطا را مدیریت کنی:
csharp
try
{
var author = _context.Authors.Find(id);
_context.Authors.Remove(author);
_context.SaveChanges();
return RedirectToAction("Index");
}
catch (DbUpdateException ex)
{
TempData["DeleteError"] = "نمیتوان نویسندهای که کتاب دارد را حذف کرد.";
return RedirectToAction("Index");
}
🔹 اگر نویسنده کتاب داشته باشد، حذف ممنوع است و EF Core خطا میدهد
🔹 با catch این خطا را میگیری و پیام مناسب به کاربر نمایش میدهی
🔹 از TempData برای نمایش پیام در صفحه لیست استفاده میکنی
---
✨ نکات حرفهای
- همیشه قبل از SaveChanges() از try-catch استفاده کن وقتی محدودیت دیتابیس داری
- میتونی از ex.InnerException.Message برای تشخیص نوع خطا استفاده کنی
- بهتره قبل از رسیدن به خطای دیتابیس، با Any() یا Count() بررسی کنی تا کاربر تجربه بهتری داشته باشه
پروژه ASP.Net Core MVC (وب و سی شارپ)
🎯 درس جدید: تنظیم دقیق مدلها با ModelBuilder در EF Core در این مرحله از پروژه مدیریت نویسنده و کتا
الان میخوای بدونی چرا این کوئریها با اینکه شبیه هم هستن، هرکدوم ساختار متفاوتی دارن و چه زمانی باید از هرکدوم استفاده کرد. بیایم با دستهبندی، مثال، و توضیح کامل همه کوئریها رو بررسی کنیم تا هیچ ابهامی باقی نمونه.
---
🧠 دستهبندی کلی کوئریها
تو ۷ کوئری دادی که میتونیم به ۳ دسته تقسیم کنیم:
| دسته | هدف | شروع از |
|------|------|----------|
| ➊ واکشی کتابها با نام نویسنده | نمایش لیست کتابها | Books |
| ➋ واکشی نویسندهها با تعداد یا لیست کتابها | گزارشگیری نویسندهمحور | Authors |
| ➌ واکشی اطلاعات خاص بر اساس authorId | فیلتر شده بر اساس نویسنده | ترکیبی |
---
🔍 بررسی دقیق هر کوئری
---
✅ ➊ کوئری اول: کتابها با نام نویسنده (تو در تو)
csharp
var books = query
.Select(b => new
{
b.Id,
b.Title,
b.IsAvailable,
AuthorName = _context.Authors
.Where(a => a.Id == b.AuthorId)
.Select(a => a.FullName)
.FirstOrDefault()
})
.ToList();
🔹 ویژگیها:
- از Books شروع میکنی
- برای هر کتاب، با AuthorId میری سراغ جدول Authors
- Select تو در تو باعث میشه EF پشتصحنه JOIN بزنه
- مناسب برای لیست کتابها با نام نویسنده
🔸 نکته مهم: اگر b.Author بهصورت Navigation Property تعریف شده باشه، بهتره از b.Author.FullName استفاده کنی (مثل کوئری ➐)
---
✅ ➋ کوئری دوم: نویسندهها با تعداد کتابها
csharp var authors = _context.Authors .Select(a => new { a.Id, a.FullName, BookCount = _context.Books.Count(b => b.AuthorId == a.Id) }) .ToList();🔹 ویژگیها: - از Authors شروع میکنی - برای هر نویسنده، تعداد کتابهاش رو با Count محاسبه میکنی - مناسب برای داشبورد آماری یا گزارشگیری --- ✅ ➌ کوئری سوم و چهارم: واکشی اطلاعات خاص بر اساس authorId
csharp var authorName = _context.Authors .Where(a => a.Id == authorId) .Select(a => a.FullName) .FirstOrDefault(); var books = _context.Books .Where(b => b.AuthorId == authorId) .Select(b => new { b.Id, b.Title, b.IsAvailable }) .ToList();🔹 ویژگیها: - جدا جدا اطلاعات نویسنده و کتابهاش رو میگیری - مناسب برای صفحه جزئیات نویسنده یا فیلتر شده بر اساس انتخاب کاربر --- ✅ ➍ کوئری پنجم: نویسندهها با تعداد و لیست کتابهای اخیر
csharp var authors = _context.Authors .Select(a => new { a.Id, a.FullName, BookCount = _context.Books.Count(b => b.AuthorId == a.Id), Books = _context.Books .Where(b => b.AuthorId == a.Id) .OrderByDescending(b => b.Id) .Take(6) .Select(b => new { b.Id, b.Title, b.IsAvailable }).ToList() }) .ToList();🔹 ویژگیها: - ترکیب Count و Select تو در تو - برای هر نویسنده، ۶ کتاب آخرش رو میگیری - مناسب برای صفحه نویسنده با خلاصه آثار 🔸 نکته مهم: چون از _context.Books جدا استفاده میکنی، EF ممکنه کوئریهای جداگانه بزنه (وابسته به تنظیمات) --- ✅ ➎ کوئری ششم: نویسندهها با لیست عنوان کتابها (با Navigation)
csharp var authors = _context.Authors .Select(a => new { a.FullName, Books = a.Books.Select(b => b.Title).ToList() }) .ToList();🔹 ویژگیها: - از Authors شروع میکنی - از a.Books استفاده میکنی که باید Navigation Property باشه - ساده و بهینه، مناسب برای نمایش آثار نویسنده 🔸 نکته مهم: اگر Books در مدل Author تعریف نشده باشه، این کد خطا میده --- ✅ ➏ کوئری هفتم: کتابها با نام نویسنده (با Navigation)
csharp var books = _context.Books .Select(b => new { b.Title, b.IsAvailable, AuthorName = b.Author.FullName }) .ToList();🔹 ویژگیها: - سادهترین و بهینهترین روش - از b.Author.FullName استفاده میکنی که باید Navigation Property باشه - مناسب برای لیست کتابها با اطلاعات نویسنده --- 🧩 تفاوتهای کلیدی بین کوئریها
پروژه ASP.Net Core MVC (وب و سی شارپ)
🎯 درس جدید: تنظیم دقیق مدلها با ModelBuilder در EF Core در این مرحله از پروژه مدیریت نویسنده و کتا
| کوئری | شروع از | نوع Select | نیاز به Navigation | کاربرد |
|-------|----------|---------------|---------------------|---------|
| ➊ | Books | تو در تو | نه | لیست کتابها با نویسنده |
| ➋ | Authors | Count | نه | تعداد کتابها |
| ➌ | ترکیبی | جداگانه | نه | فیلتر شده بر اساس نویسنده |
| ➍ | Authors | Count + Select تو در تو | نه | لیست محدود کتابها |
| ➎ | Authors | Select ساده | بله | لیست عنوان کتابها |
| ➏ | Books | Select ساده | بله | لیست کتابها با نویسنده |
---
🎯 جملههای یادسپاری برای جلوگیری از اشتباه
- اگر از جدول شروع میکنی، فقط به فیلدهای همون جدول مستقیم دسترسی داری
- اگر میخوای اطلاعات جدول مرتبط رو بیاری، باید از Select تو در تو یا Navigation استفاده کنی
- اگر از ToList() زودتر استفاده کنی، باید Include بزنی تا اطلاعات مرتبط لود بشه
- اگر Navigation Property نداری، نمیتونی از b.Author.FullName استفاده کنی
پروژه ASP.Net Core MVC (وب و سی شارپ)
ویرایش پروژه
این سه بخش از پروژه BookSelect که گفتی، هرکدوم هدف مشخصی دارن و با هم هماهنگ هستن. بیایم دقیق و خلاصه توضیح بدیم:
---
## ✅ 1. فیلتر نمایش ندادن نویسندههای بدون کتاب در صفحه اصلی
در کنترلر
Indexاز این شرط استفاده شده:
.Where(a => _context.Books.Any(b => b.AuthorId == a.Id))این یعنی فقط نویسندههایی واکشی میشن که حداقل یک کتاب دارن. ✅ باعث میشه نویسندههای بدون کتاب اصلاً در لیست صفحه اصلی دیده نشن ✅ تعداد صفحات هم بر اساس همین فیلتر محاسبه میشه --- ## ✅ 2. غیرفعال کردن دکمه "کتابهای بیشتر" برای نویسندههای بدون کتاب در View از شرط
BookCount > 0استفاده میکنی:
@if (author.BookCount > 0) { <a href="..." class="btn btn-outline-primary">کتابهای بیشتر</a> } else { <button class="btn btn-outline-secondary" disabled>کتابی ندارد</button> }✅ وقتی نویسنده کتاب نداره، دکمه لینکدار نمایش داده نمیشه ✅ بهجاش یه دکمه غیرفعال با پیام مناسب نشون داده میشه ✅ تجربه کاربری بهتر و بدون خطا --- ## ✅ 3. استفاده از `AsNoTracking()` در حذف نویسنده در اکشن
DeleteConfirmedاز این خط استفاده شده:
var author = _context.Authors .AsNoTracking() .Include(a => a.Books) .FirstOrDefault(a => a.Id == id);✅
AsNoTracking()یعنی EF Core دادهها رو فقط برای خواندن واکشی میکنه ✅ چون قرار نیست
authorتغییر داده بشه (فقط بررسی و حذف میشه)، ردیابی لازم نیست ✅ باعث افزایش سرعت و کاهش مصرف حافظه میشه ✅ مناسب برای عملیاتهایی مثل حذف، که فقط بررسی و تصمیمگیری انجام میشه --- ## 🎯 جمعبندی: | بخش | هدف | نتیجه | |-----|------|--------| | فیلتر نویسندهها | حذف نویسندههای بدون کتاب از لیست | نمایش دقیق و مرتبط | | دکمه کتاب بیشتر | کنترل نمایش دکمه بر اساس تعداد کتاب | تجربه کاربری بهتر | | AsNoTracking | واکشی سبک و سریع برای حذف | بهینهسازی عملکرد |
پروژه ASP.Net Core MVC (وب و سی شارپ)
پروژه فروشگاه با سفارش
بیایم یک جمعبندی کامل از کارهایی که تا الان روی پروژه انجام دادیم و امکاناتی که پروژه داره رو لیست کنیم تا تصویر روشنی داشته باشی:
---
## ✅ کارهایی که انجام دادیم
1. مدیریت سفارشها (Orders)
- ساخت اکشن
Indexبرای نمایش لیست سفارشها - ساخت اکشن
Detailsبرای نمایش جزئیات یک سفارش - استفاده از
Includeو
ThenIncludeبرای بارگذاری محصولات هر سفارش - مرتبسازی سفارشها بر اساس تاریخ (
OrderByDescending) 2. نمایش وضعیت سفارش (Status) - تعریف
Enumبرای وضعیت سفارش (مثل Pending, Confirmed, Shipped, Canceled) - ساخت کلاس کمکی
EnumHelperبرای گرفتن متن فارسی از
Display(Name = "...")- تبدیل مقدار
Enumبه متن فارسی در کنترلر و ارسال به View - نمایش متن فارسی وضعیت در لیست سفارشها و جزئیات سفارش 3. مدیریت محصولات (Products) - اکشن
Editبرای ویرایش محصول - بررسی تکراری نبودن نام محصول - بررسی تغییر وضعیت موجودی (
IsAvailable) - اگر محصول از «موجود» به «ناموجود» تغییر کند و در سفارشها باشد → نمایش هشدار برای حذف از سفارشها - ساخت اکشن
ConfirmProductRemovalبرای نمایش صفحه تأیید - ساخت اکشن
RemoveProductFromOrdersبرای حذف محصول از سفارشها و غیرفعال کردن آن 4. بهبود تجربه کاربری - نمایش پیامهای موفقیت و خطا با
TempDataدر View - نمایش هشدار قبل از حذف محصول از سفارشها - جلوگیری از حذف ناخواسته با شرط بررسی وضعیت قبلی و جدید محصول --- ## 📦 امکانات فعلی پروژه - مدیریت سفارشها - لیست سفارشها با نام مشتری، تاریخ، وضعیت فارسی، تعداد محصولات و مبلغ کل - جزئیات سفارش شامل اطلاعات مشتری و لیست محصولات سفارش - مدیریت محصولات - افزودن محصول جدید - ویرایش محصول (نام، قیمت، وضعیت موجودی) - بررسی تکراری نبودن نام محصول - هشدار و حذف محصول از سفارشها در صورت غیرفعال شدن - زیرساخت فنی - استفاده از ASP.NET Core MVC - استفاده از Entity Framework Core برای ارتباط با دیتابیس - بارگذاری دادههای مرتبط با
Includeو
ThenInclude- استفاده از
Enumو
DisplayAttributeبرای وضعیتها - استفاده از ViewBag و TempData برای ارسال دادهها و پیامها به View --- ## 🔍 چرا
Shop & Ordersتبدیل شده به `Shop___Orders`؟ - در نامفضا (namespace) یا **اسم پروژه**، کاراکترهایی مثل فاصله (
)، علامت & (
&)، خط تیره (
-) و… مجاز نیستند. - وقتی تو اسم پروژه یا فولدرت رو گذاشتی
Shop & Orders`، کامپایلر یا ابزارهای EF Core و Visual Studio اومدن اون کاراکتر غیرمجاز (`&و فاصله) رو جایگزین کنن. - جایگزینی پیشفرض اینه که هر کاراکتر غیرمجاز → تبدیل به
_(خط زیر). - چون هم فاصله داشتی و هم `&`، چند بار جایگزینی انجام شده و نتیجه شده:
Shop___Ordersیعنی: - `Shop` ✅ - فاصله →
_-
&→
_- فاصله بعدی →
_-
Orders✅