eitaa logo
پروژه ASP.Net Core MVC (وب و سی شارپ)
119 دنبال‌کننده
168 عکس
38 ویدیو
376 فایل
❁﷽❁ آموزش 📖 برنامه نویسی ASP.Net Core MVC (وب و سی شارپ) Admin: @alialirezapanahi برنامه نویسی برنامه نویسی سی شارپ eitaa.com/sisharpapp برنامه نویسی وب eitaa.com/aspdatnet ویراستی virasty.com/alialirezapanahi آپارات aparat.com/alialirezapanahi
مشاهده در ایتا
دانلود
پروژه 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
Shop & Orders (2).zip
حجم: 24.9M
این دو قطعه کد با هم کار می‌کنن تا وقتی کاربر هیچ محصولی انتخاب نکرده، یک پیام خطا به‌صورت واضح در صفحه نمایش داده بشه. بیایم مرحله‌به‌مرحله و ساده بررسی کنیم که هر کدوم چه کاری انجام می‌دن: --- ## 🧩 بخش اول: کنترلر – اعتبارسنجی انتخاب محصول if (selectedProductIds == null || !selectedProductIds.Any()) { ModelState.AddModelError("", "حداقل یک محصول باید انتخاب شود"); } ### ✅ توضیح: -
selectedProductIds == null
یعنی هیچ لیستی ارسال نشده -
!selectedProductIds.Any()
یعنی لیست خالیه (هیچ محصولی انتخاب نشده) - اگر یکی از این دو شرط برقرار باشه، یعنی کاربر هیچ محصولی انتخاب نکرده ### 🔔 نتیجه: با ModelState.AddModelError("", "...") یک خطا به مدل اضافه می‌شه 🔹 چون کلید خالی (
""
) استفاده شده، این خطا به هیچ فیلد خاصی وصل نیست 🔹 پس باید با
ValidationSummary
نمایش داده بشه --- ## 🧩 بخش دوم: View – نمایش پیام خطا @Html.ValidationSummary(true, "", new { @class = "text-danger" }) ### ✅ توضیح: -
true
یعنی خطاهای غیرفیلدی هم نمایش داده بشن (مثل همین مورد که کلیدش
""
هست) -
""
یعنی هیچ متن اضافی قبل از لیست خطاها نمایش داده نشه -
new { @class = "text-danger" }
یعنی خطاها با رنگ قرمز (کلاس Bootstrap) نمایش داده بشن --- ## 🧠 مثال تصویری در صفحه: اگر کاربر هیچ محصولی انتخاب نکنه، این پیام در بالای فرم نمایش داده می‌شه: ❌ حداقل یک محصول باید انتخاب شود و چون
text-danger
استفاده شده، قرمز دیده می‌شه.
لیستی کامل و دسته‌بندی‌شده از مهم‌ترین کدهای Fluent API در Entity Framework Core برات آماده کردم—با توضیح فارسی کنار هر کد، تا هم راحت یاد بگیری، هم اشتباه نکنی. --- ## 🔷 ۱. تنظیم پراپرتی‌ها (Property Configuration) entity.Property(x => x.Name).IsRequired(); // اجباری بودن فیلد entity.Property(x => x.Name).HasMaxLength(100); // محدودیت طول entity.Property(x => x.Price).HasColumnType("decimal(18,2)"); // نوع دیتابیس entity.Property(x => x.CreatedAt).HasDefaultValueSql("GETDATE()"); // مقدار پیش‌فرض از SQL entity.Property(x => x.IsActive).HasDefaultValue(true); // مقدار پیش‌فرض بولی entity.Property(x => x.Description).IsUnicode(false); // ذخیره به‌صورت غیر یونیکد --- ## 🔷 ۲. تنظیم کلید اصلی و کلید خارجی entity.HasKey(x => x.Id); // کلید اصلی entity.HasAlternateKey(x => x.Code); // کلید جایگزین (Unique) entity.HasIndex(x => x.Email).IsUnique(); // ایندکس یکتا entity.HasIndex(x => new { x.Title, x.AuthorId }).IsUnique(); // ایندکس ترکیبی یکتا --- ## 🔷 ۳. تنظیم رابطه‌ها (Navigation & Relationships) ### 🔹 یک‌به‌چند (One-to-Many) entity.HasMany(x => x.Books) .WithOne(x => x.Author) .HasForeignKey(x => x.AuthorId) .OnDelete(DeleteBehavior.Restrict); // جلوگیری از حذف نویسنده دارای کتاب ### 🔹 یک‌به‌یک (One-to-One) entity.HasOne(x => x.Profile) .WithOne(x => x.User) .HasForeignKey<UserProfile>(x => x.UserId); ### 🔹 چند‌به‌چند (Many-to-Many) entity.HasMany(x => x.Tags) .WithMany(x => x.Posts) .UsingEntity(j => j.ToTable("PostTags")); // جدول واسط --- ## 🔷 ۴. تغییر نام جدول و ستون entity.ToTable("Authors"); // نام جدول entity.Property(x => x.FullName).HasColumnName("AuthorName"); // نام ستون --- ## 🔷 ۵. تنظیم رفتار حذف (Delete Behavior)
.OnDelete(DeleteBehavior.Cascade); // حذف همراه با وابسته‌ها
.OnDelete(DeleteBehavior.Restrict); // جلوگیری از حذف اگر وابسته وجود دارد
.OnDelete(DeleteBehavior.SetNull); // مقدار کلید خارجی null می‌شود
--- ## 🔷 ۶. تنظیم ترتیب و ترتیب بارگذاری entity.HasIndex(x => x.CreatedAt).HasDatabaseName("IX_CreatedAt"); // نام ایندکس entity.HasData(new Author { Id = 1, FullName = "علیرضا" }); // مقدار اولیه (Seed Data) --- ## ✨ جمله یادسپاری: > «Fluent API یعنی کنترل دقیق ساخت جدول‌ها، رابطه‌ها، محدودیت‌ها و رفتارها—با کدهای زنجیره‌ای و قابل فهم.»
بیایم بررسی کنیم که آیا در این خط ساده:
var author = _context.Authors.Find(id);
استفاده از
.AsNoTracking()
لازم هست یا نه. --- ## 🧩 اول بفهمیم
.Find(id)
چی‌کار می‌کنه -
Find(id)
از EF Core استفاده می‌کنه تا رکوردی با کلید اصلی (
Id
) رو پیدا کنه - این متد همیشه با Tracking کار می‌کنه - یعنی EF تغییرات روی
author
رو ردگیری می‌کنه و اگر بعداً
SaveChanges()
بزنی، تغییرات ذخیره می‌شن --- ## ✅ آیا می‌تونی
.AsNoTracking()
بزنی؟ نه ❌ روی
Find(id)
نمی‌تونی
.AsNoTracking()
بزنی چون
Find()
از ردگیری داخلی EF استفاده می‌کنه و اگر قبلاً اون رکورد رو لود کرده باشه، از حافظه خودش برمی‌داره. --- ## 🔧 اگر بخوای نسخه بدون Tracking داشته باشی: باید از
FirstOrDefault()
یا
SingleOrDefault()
استفاده کنی:
var author = _context.Authors
    .AsNoTracking()
    .FirstOrDefault(a => a.Id == id);
✅ این نسخه داده رو بدون ردگیری میاره، مناسب برای نمایش فقط ❌ ولی اگر بخوای داده رو ویرایش کنی، نباید
AsNoTracking()
بزنی --- ## ✨ جمله یادسپاری: > «
Find(id)
همیشه با Tracking کار می‌کنه—اگر فقط می‌خوای نمایش بدی، از
FirstOrDefault
با
AsNoTracking
استفاده کن.» ---
سلام دوستان عزیز 🌱 می‌خواستم یه نکته مهم رو باهاتون در میون بذارم: من تولیدکننده حرفه‌ای محتوا نیستم، فقط یه علاقه‌مند به برنامه‌نویسی‌ام که مثل خیلی از شما، در مسیر یادگیری قدم گذاشته. با توجه به شرایط کاری‌ام، فقط جمعه‌ها فرصت دارم که تمرین کنم و چیزهایی که یاد می‌گیرم رو با شما به اشتراک بذارم. محتواهایی که منتشر می‌کنم ممکنه پایه‌ای یا برای بعضی‌ها تکراری باشه، اما برای من هر بخش کوچکی از کد یه قدم مهمه برای فهم عمیق‌تر. هدفم اینه که با تمرین‌های مداوم، حتی اگر تعداد پروژه‌ها زیاد بشه، مفاهیم رو به‌خوبی درک کنم و ملکه ذهنم بشه. اگر محتواها ساده یا ابتدایی هستن، منو ببخشید 🙏 من استاد نیستم، فقط یه یادگیرنده‌ام—مثل شما. و هر چیزی که یاد می‌گیرم، با عشق و صداقت منتشر می‌کنم.
BookSelect (4).zip
حجم: 24.7M
صفحه‌بندی پیشرفته با Razor و Bootstrap در این ساختار، فقط چند شماره اطراف صفحه فعلی نمایش داده می‌شن، با دکمه‌های «اول»، «قبلی»، «بعدی» و «آخر» برای حرکت سریع. نقطه‌چین‌ها قبل و بعد از صفحات، به کاربر کمک می‌کنن مسیر طولانی رو بهتر درک کنه. ظاهر با کلاس‌های Bootstrap طراحی شده تا هم زیبا باشه، هم واکنش‌گرا.
Shop & Orders (3).zip
حجم: 24.9M
ساده کردن کدهای enum helper ساده‌سازی نمایش Enum در پروژه‌های MVC برای تبدیل مقادیر Enum به متن قابل‌نمایش (مثل فارسی)، می‌تونیم از ویژگی
[Display(Name = "...")]
استفاده کنیم. به‌جای نوشتن کدهای طولانی در کنترلر، با ساخت یک تابع ساده مثل `GetDisplayName()`، هم در کنترلر و هم در View می‌تونیم متن مناسب رو دریافت کنیم. این کار باعث تمیز شدن کد، کاهش تکرار، و افزایش خوانایی پروژه می‌شه.
پروژه ASP.Net Core MVC (وب و سی شارپ)
ویرایش پروژه
بیایم این چهار بخش کد رو مرحله‌به‌مرحله بررسی کنیم تا دقیقاً بدونی چه تفاوت‌هایی دارن و کد درست برای فرم ویرایش چیه: --- ## ✅ 1. لیست ساده با
Select
و آبجکت ناشناس ViewBag.Authors = _context.Authors .Select(a => new { a.Id, a.FullName }) .ToList(); - فقط یه لیست ساده از
Id
و
FullName
می‌سازه - خروجی:
List<object>
- ❌ برای DropDown قابل استفاده نیست چون ساختارش مناسب
asp-items
نیست --- ## ✅ 2. لیست آماده با
SelectList
ViewBag.Authors = new SelectList(_context.Authors.ToList(), "Id", "FullName"); - ساختار مناسب برای DropDown - خروجی:
SelectList
- ✅ در View با
asp-items="ViewBag.Authors"
قابل استفاده - ❌ اگر مقدار انتخاب‌شده رو مشخص نکنی، DropDown خالی می‌مونه --- ## ✅ 3. بررسی وجود کتاب تکراری در فرم ویرایش
bool exists = _context.Books
    .Any(b => b.Title == book.Title && b.AuthorId == book.AuthorId);

if (exists)
{
    ModelState.AddModelError("Title", "این نویسنده قبلاً کتابی با این عنوان دارد.");
}
- بررسی می‌کنه که آیا همین نویسنده قبلاً کتابی با همین عنوان ثبت کرده یا نه - اگر بله، خطا به
ModelState
اضافه می‌شه و فرم دوباره نمایش داده می‌شه - ✅ این بخش کاملاً درسته و برای جلوگیری از داده‌های تکراری استفاده می‌شه ❌ ولی برای افزودن و برای ویرایش مناسب نیست --- ## ✅ 4. ساخت دستی لیست DropDown با
SelectListItem
ViewBag.Authors = _context.Authors .Select(a => new SelectListItem { Value = a.Id.ToString(), Text = a.FullName }) .ToList(); - خروجی:
List<SelectListItem>
- ✅ قابل استفاده در View با
asp-items="ViewBag.Authors"
- می‌تونی برای هر آیتم
Selected = true
بزنی - مناسب برای فرم‌هایی که مقدار انتخاب‌شده رو از قبل داری --- ## 🔍 نتیجه‌گیری کلی: | روش | خروجی | مناسب DropDown | کنترل انتخاب‌شده | |------|--------|----------------|-------------------| | Select با آبجکت ناشناس | List<object> | ❌ | ❌ | | SelectList | SelectList | ✅ | با پارامتر چهارم | | SelectListItem دستی | List<SelectListItem> | ✅ | با
Selected = true
| --- ## ✨ جمله یادسپاری: > «در فرم ویرایش، یا از SelectList با پارامتر چهارم استفاده کن، یا از SelectListItem با شرط Selected—هر دو روش حرفه‌ای هستن.»