بیایید به طور جامع تمامی این کدها را با هم بررسی کنیم و هر بخش از آنها را توضیح دهیم تا درک بهتری از ساختار و روابط بین این موجودیتها (Entities) داشته باشیم.
1. کد Customer
namespace WebApplication5.Models.Entities
{
public class Customer
{
public long Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Name { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
}
ویژگیها: Id (شناسه مشتری)، UserName (نام کاربری)، Password (رمز عبور)، Name (نام کامل).
رابطه: Orders یک مجموعه از Order که این مشتری انجام داده است.
2. کد Order
namespace WebApplication5.Models.Entities
{
public class Order
{
public long Id { get; set; }
public DateTime CraetDate { get; set; }
public string Address { get; set; }
public virtual Customer Customer { get; set; }
public long CustomerId { get; set; }
public virtual ICollection<OrderDetil> OrderDetils { get; set; }
}
}
ویژگیها: Id (شناسه سفارش)، CraetDate (تاریخ ایجاد سفارش)، Address (آدرس مشتری).
رابطهها:
Customer، مرجعی به مشتری که سفارش را ثبت کرده است.
CustomerId، کلید خارجی که به مشتری اشاره میکند.
OrderDetils، مجموعهای از جزئیات سفارش که به این سفارش تعلق دارد.
3. کد OrderDetil
namespace WebApplication5.Models.Entities
{
public class OrderDetil
{
public long Id { get; set; }
public int Count { get; set; }
public virtual Order Order { get; set; }
public long OrderId { get; set; }
public virtual Product Product { get; set; }
public long ProductId { get; set; }
}
}
ویژگیها: Id (شناسه جزئیات سفارش)، Count (تعداد محصول).
رابطهها:
Order، مرجعی به سفارش که این جزئیات به آن تعلق دارد.
OrderId، کلید خارجی که به سفارش اشاره میکند.
Product، مرجعی به محصولی که این جزئیات به آن تعلق دارد.
ProductId، کلید خارجی که به محصول اشاره میکند.
4. کد Product
namespace WebApplication5.Models.Entities
{
public class Product
{
internal object warranty;
public long Id { get; set; }
public string Images { get; set; }
public string Name { get; set; }
public string Brand { get; set; }
public int Price { get; set; }
public float Ram { get; set; }
public OStype OS { get; set; }
public string Network { get; set; }
public int Inventory { get; set; }
public virtual ICollection<OrderDetil> OrderDetils { get; set; }
public Warranty Warranty { get; set; }
}
public enum OStype
{
IOS = 0,
Androide = 1,
WindowsPhone = 2
}
}
ویژگیها: Id (شناسه محصول)، Images (تصاویر محصول)، Name (نام محصول)، Brand (برند محصول)، Price (قیمت محصول)، Ram (حافظه رم)، OS (سیستم عامل)، Network (نوع شبکه)، Inventory (موجودی).
رابطهها:
OrderDetils، مجموعهای از جزئیات سفارش که به این محصول تعلق دارد.
Warranty، مرجعی به گارانتی محصول.
5. کد Warranty
namespace WebApplication5.Models.Entities
{
public class Warranty
{
public Product Product { get; set; }
public long ProductId { get; set; }
public int WarrantyPeriod { get; set; }
}
}
ویژگیها: Product (مرجعی به محصول مرتبط)، ProductId (کلید خارجی که به محصول اشاره میکند)، WarrantyPeriod (مدت زمان گارانتی).
6. کد DatabaseContext
using Microsoft.EntityFrameworkCore;
using WebApplication5.Models.Entities;
namespace WebApplication5.Models.Context
{
public class DatabaseContext : DbContext
{
public DatabaseContext()
{
}
public DbSet<Customer> Customers { get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Data Source=DESKTOP-3PDBPI3\SQLEXPRESS; Initial Catalog=StoreEf; Integrated Security=True; TrustServerCertificate=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Warranty>().HasKey(p => p.ProductId);
modelBuilder.Entity<Product>().HasOne(p => p.Warranty).WithOne(p => p.Product).HasForeignKey<Warranty>(p => p.ProductId);
modelBuilder.Entity<Customer>().Property(e => e.Name).HasColumnName("FullName").HasColumnType("nvarchar(50)");
}
}
}
ویژگیها:
Customers، مجموعهای از مشتریان.
Products، مجموعهای از محصولات.
OnConfiguring: پیکربندی اتصال به پایگاه داده SQL Server.
OnModelCreating: تنظیم مدلها و روابط بین موجودیتها.
نتیجهگیری
این مجموعه کدها نشاندهندهی مدلسازی دادهها با استفاده از Entity Framework Core است که شامل کلاسهای Customer، Order، OrderDetil، Product و Warranty میباشد. همچنین شامل یک کلاس DatabaseContext است که وظیفه مدیریت اتصال به پایگاه داده و پیکربندی مدلها را بر عهده دارد. این ساختار به شما امکان میدهد تا به صورت شیءگرا با پایگاه داده تعامل کنید و دادهها را مدیریت کنید.
و در آخر نتیجه کار
در پک منیجر Add-Migration InitialCompelet
را اضافه می کنید تا Migration ساخته شود و Update-Database
را هم می زنیم تا اتصال در دیتابیس بر قرار می شود و جدول ها ایجاد شوند
WebApplication5.zip
حجم:
16.6M
پروژه asp.net core mvc اتصال به دیتابیس و ایجاد جدول ها
DbContext و الگوهای Repository و Unit of Work
این DbContext در Entity Framework Core به خودی خود یک پیادهسازی از الگوی Unit of Work است. همچنین، DbSetهای آن نقش مخزن (Repository) را ایفا میکنند. بنابراین، بسیاری از توسعهدهندگان بر این باورند که افزودن لایههای اضافی برای Repository و Unit of Work بر روی DbContext غیر ضروری و غیر کاربردی است و میتواند به عنوان آنتیپترن شناخته شود.
دلایل استفاده مستقیم از DbContext:
- سادگی و کاهش پیچیدگی:
استفاده مستقیم از DbContext باعث کاهش پیچیدگی و نگهداری کد میشود. نیاز نیست که لایههای اضافی Repository و Unit of Work را مدیریت کنید.
- کاهش کد اضافی:
افزودن لایههای اضافی Repository و Unit of Work معمولاً به نوشتن کد تکراری و اضافی منجر میشود که ممکن است به پیچیدگی بیشتر و نگهداری سختتر بیانجامد.
- پشتیبانی کامل از EF Core:
در DbContext از تمامی قابلیتها و ویژگیهای EF Core به طور کامل پشتیبانی میکند. استفاده مستقیم از آن به شما امکان میدهد تا از تمام قابلیتها و انعطافپذیری EF Core بهرهمند شوید.
مثال ساده از استفاده مستقیم DbContext:
در اینجا یک نمونه ساده از استفاده مستقیم DbContext در کنترلر آورده شده است:
public class CustomersController : Controller
{
private readonly DatabaseContext _context;
public CustomersController(DatabaseContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
var customers = await _context.Customers.ToListAsync();
return View(customers);
}
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Customer customer)
{
if (ModelState.IsValid)
{
_context.Add(customer);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(customer);
}
}
در این کد، مستقیماً از DbContext استفاده میکنیم تا دادهها را از پایگاه داده دریافت کرده و عملیات CRUD را انجام دهیم.
آنتیپترن بودن افزودن لایه Repository و Unit of Work:
افزودن لایههای Repository و Unit of Work به عنوان آنتیپترن شناخته میشود زیرا:
- افزایش پیچیدگی بدون افزودن ارزش واقعی: با توجه به این که DbContext خود یک پیادهسازی از Unit of Work و Repository است، افزودن لایههای اضافی بدون افزودن ارزش واقعی به کد، تنها پیچیدگی را افزایش میدهد.
- کاهش عملکرد و بهرهوری: لایههای اضافی میتوانند باعث کاهش عملکرد و بهرهوری شوند زیرا به کد اضافی و هزینههای اضافی نیاز دارند.
نتیجهگیری:
استفاده مستقیم از DbContext به عنوان واحد کاری (Unit of Work) و مخزن (Repository) معمولاً به عنوان بهترین عمل شناخته میشود و از افزودن لایههای اضافی خودداری میشود. این رویکرد نه تنها پیچیدگی را کاهش میدهد بلکه از تمام قابلیتها و امکانات EF Core بهرهمند میشود. البته، بسته به نیازهای خاص پروژه شما، ممکن است موارد استثنایی وجود داشته باشد.
پوشه Models پوشه Services پوشه GetCustomerList فایل اینترفیس IGetCustomerListService.cs
using WebApplication5.Models.Context;
namespace WebApplication5.Models.Services.GetCustomerList
{
public interface IGetCustomerListService
{
List<CustomerListDto> Execute();
}
public class GetCustomerListService : IGetCustomerListService
{
private readonly DatabaseContext Context;
public GetCustomerListService()
{
Context = new DatabaseContext();
}
public List<CustomerListDto> Execute()
{
var customers = Context.Customers.Select(p => new CustomerListDto {
Id = p.Id,
Name = p.Name,
UserName = p.UserName,
}).ToList();
return customers;
}
}
public class CustomerListDto
{
public long Id { get; set; }
public string Name { get; set; }
public string UserName { get; set; }
}
}
بیایید کد شما را قدم به قدم بررسی کنیم و هر بخش از آن را توضیح دهیم:
1. افزودن وابستگیها
using WebApplication5.Models.Context;
این دستور using، فضای نام WebApplication5.Models.Context را وارد میکند که فرضاً شامل کلاس DatabaseContext است.
2. تعریف Namespace و اینترفیس
namespace WebApplication5.Models.Services.GetCustomerList
{
public interface IGetCustomerListService
{
List<CustomerListDto> Execute();
}
namespace WebApplication5.Models.Services.GetCustomerList: این بخش نشان میدهد که کدهای زیر در فضای نام WebApplication5.Models.Services.GetCustomerList قرار دارند.
public interface IGetCustomerListService: یک اینترفیس به نام IGetCustomerListService تعریف شده که شامل یک متد به نام Execute است که لیستی از CustomerListDto بازمیگرداند.
3. تعریف کلاس GetCustomerListService
public class GetCustomerListService : IGetCustomerListService
{
private readonly DatabaseContext Context;
public GetCustomerListService()
{
Context = new DatabaseContext();
}
public class GetCustomerListService : IGetCustomerListService: این کلاس از اینترفیس IGetCustomerListService پیروی میکند.
private readonly DatabaseContext Context: یک متغیر خصوصی برای نگهداری یک نمونه از DatabaseContext.
public GetCustomerListService(): سازنده کلاس که یک نمونه جدید از DatabaseContext ایجاد میکند و آن را به متغیر Context اختصاص میدهد.
4. پیادهسازی متد Execute
public List<CustomerListDto> Execute()
{
var customers = Context.Customers.Select(p => new CustomerListDto {
Id = p.Id,
Name = p.Name,
UserName = p.UserName,
}).ToList();
return customers;
}
public List<CustomerListDto> Execute(): این متد از اینترفیس پیروی کرده و پیادهسازی شده است.
Context.Customers.Select(p => new CustomerListDto { ... }).ToList();: این خط یک لیست از CustomerListDto ها بر اساس دادههای موجود در Customers جدول پایگاه داده ایجاد میکند.
return customers;: لیست ایجاد شده از مشتریان را بازمیگرداند.
5. تعریف کلاس CustomerListDto
public class CustomerListDto
{
public long Id { get; set; }
public string Name { get; set; }
public string UserName { get; set; }
}
}
public class CustomerListDto: این کلاس یک مدل دادهای ساده است که شامل اطلاعاتی از مشتری است.
ویژگیها:
Id: شناسه مشتری.
Name: نام مشتری.
UserName: نام کاربری مشتری.
نتیجهگیری
کد شما به این منظور طراحی شده است تا یک سرویس فراهم کند که لیستی از مشتریان را از پایگاه داده با استفاده از Entity Framework و DbContext بازیابی کند. این سرویس، مشتریان را انتخاب کرده و آنها را در قالب CustomerListDto بازمیگرداند. ساختار کلی شامل یک اینترفیس، یک کلاس که این اینترفیس را پیادهسازی میکند، و یک مدل دادهای برای انتقال دادههای مشتریان است.
در Program.cs
using WebApplication5.Models.Services.GetCustomerList;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddTransient<IGetCustomerListService, GetCustomerListService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
کد AddTransient<IGetCustomerListService, GetCustomerListService> بخشی از تنظیمات وابستگی (Dependency Injection) در ASP.NET Core است. بیایید به طور دقیقتر توضیح دهیم که این کد چه کاری انجام میدهد.
توضیح کلی
این کد یک سرویس (GetCustomerListService) را به سیستم تزریق وابستگی اضافه میکند و آن را به اینترفیس (IGetCustomerListService) متصل میکند. این تنظیمات به ASP.NET Core اجازه میدهد تا هر بار که یک وابستگی به IGetCustomerListService نیاز است، یک نمونه جدید از GetCustomerListService ایجاد کند.
اجزای اصلی کد
services.AddTransient<IGetCustomerListService, GetCustomerListService>();
services:
این شیء که معمولاً در متد ConfigureServices موجود است، شامل سرویسهای ثبت شده در کانتینر وابستگی است.
AddTransient:
این متد به کانتینر وابستگی ASP.NET Core میگوید که هر بار که یک وابستگی به IGetCustomerListService نیاز است، یک نمونه جدید از GetCustomerListService ایجاد کند. Transient به این معناست که هر بار که این سرویس درخواست میشود، یک نمونه جدید از کلاس مورد نظر ایجاد میشود. این مورد برای سرویسهایی مناسب است که وضعیت داخلی ندارند یا نیاز است که هر بار یک نمونه جدید ایجاد شود.
IGetCustomerListService:
این اینترفیس نمایانگر قرارداد سرویس است که تعریف میکند چه متدهایی باید توسط پیادهسازیها ارائه شود.
GetCustomerListService:
این کلاس پیادهسازی اینترفیس است و شامل منطق واقعی برای انجام عملیاتهای تعریف شده در اینترفیس میباشد.
مثال کاربردی
با ثبت این سرویس در کانتینر وابستگی، شما میتوانید آن را به هر کلاسی که نیاز به استفاده از این سرویس دارد، تزریق کنید. به عنوان مثال، در یک کنترلر میتوان به این شکل از سرویس استفاده کرد:
public class CustomerController : Controller
{
private readonly IGetCustomerListService _getCustomerListService;
public CustomerController(IGetCustomerListService getCustomerListService)
{
_getCustomerListService = getCustomerListService;
}
public IActionResult Index()
{
var customers = _getCustomerListService.Execute();
return View(customers);
}
}
نتیجهگیری
کد AddTransient<IGetCustomerListService, GetCustomerListService> به شما این امکان را میدهد که از سیستم تزریق وابستگی ASP.NET Core استفاده کنید تا مدیریت ایجاد و حفظ وابستگیهای سرویسها سادهتر شود. با استفاده از این روش، میتوانید به راحتی سرویسهای خود را تست و مدیریت کنید و از تکرار کد جلوگیری کنید.
ایجاد کنترلر و نام کنترلر: CustomerController.cs و کد های زیر
public class CustomerController : Controller
{
private readonly IGetCustomerListService _getCustomerListService;
public CustomerController(IGetCustomerListService getCustomerListService)
{
_getCustomerListService = getCustomerListService;
}
// GET: CustomerController
public ActionResult Index()
{
return View(_getCustomerListService.Execute());
}
بیایید کد شما را به تفصیل بررسی کنیم و هر بخش از آن را توضیح دهیم:
تعریف کلاس کنترلر
public class CustomerController : Controller
{
public class CustomerController :
Controller:
این بخش نشان میدهد که CustomerController یک کلاس عمومی است که از کلاس Controller به ارث برده است. در ASP.NET Core، کنترلرها مسئول مدیریت درخواستهای HTTP و برگرداندن پاسخ مناسب به کاربر هستند.
تعریف فیلد خصوصی برای سرویس
private readonly IGetCustomerListService _getCustomerListService;
private readonly IGetCustomerListService
_getCustomerListService:
این خط یک فیلد خصوصی و فقط خواندنی (readonly) به نام _getCustomerListService از نوع اینترفیس IGetCustomerListService تعریف میکند. این فیلد برای نگهداری یک نمونه از سرویس IGetCustomerListService استفاده میشود.
سازنده کلاس
public CustomerController(IGetCustomerListService getCustomerListService)
{
_getCustomerListService = getCustomerListService;
}
public
CustomerController(IGetCustomerListService getCustomerListService):
این سازنده کلاس CustomerController است که یک پارامتر از نوع IGetCustomerListService دریافت میکند.
_getCustomerListService = getCustomerListService:
در داخل سازنده، نمونهای از IGetCustomerListService که از طریق تزریق وابستگی (Dependency Injection) دریافت شده است، به فیلد خصوصی _getCustomerListService اختصاص داده میشود. این روش به کنترلر اجازه میدهد تا از سرویس IGetCustomerListService استفاده کند.
متد Index
// GET: CustomerController
public ActionResult Index()
{
return View(_getCustomerListService.Execute());
}
}
public ActionResult Index():
این متد یک اکشن به نام Index در کنترلر CustomerController تعریف میکند. این اکشن زمانی اجرا میشود که درخواست GET به آدرس /Customer ارسال شود.
return View(_getCustomerListService.Execute()):
این خط یک ویو (View) را برمیگرداند و دادههای مشتریان را که از طریق متد Execute در سرویس _getCustomerListService بازیابی شدهاند، به ویو ارسال میکند. متد Execute یک لیست از CustomerListDto بازمیگرداند که به ویو ارسال میشود تا نمایش داده شود.
خلاصه
کد شما یک کنترلر به نام CustomerController ایجاد میکند که شامل یک اکشن به نام Index است. این کنترلر از یک سرویس IGetCustomerListService استفاده میکند تا لیستی از مشتریان را بازیابی کرده و آن را به ویو ارسال کند. با استفاده از تزریق وابستگی، نمونهای از سرویس IGetCustomerListService به کنترلر تزریق میشود و از آن برای اجرای منطق بازیابی دادهها استفاده میشود.
این ساختار به شما کمک میکند تا منطق کسب و کار را از منطق ارائه (presentation logic) جدا کنید و کد خود را ماژولار و تستپذیر کنید.