آموزش Entity Framework Core
⚡ خلاصه سریع — اصل کاریها
اینها مهمترین چیزهایی هستن که اگه هیچی ندونی، فقط اینا رو بدونی کافیه:
- نکته ۱: EF Core یک ORM است که جدولهای دیتابیس رو به کلاسهای C# تبدیل میکنه.
- نکته ۲: DbContext نقطه اصلی اتصال به دیتابیس است.
- نکته ۳: DbSet
نماینده یک جدول در دیتابیس است. - نکته ۴: با LINQ کوئری مینویسی، نه SQL مستقیم.
- نکته ۵: برای ذخیره تغییرات همیشه SaveChanges() رو صدا کن.
- نکته ۶: Migration ساختار دیتابیس رو میسازه و تغییر میده.
- نکته ۷: Include باعث لود دادههای مرتبط میشود.
- نکته ۸: AsNoTracking برای کوئریهای فقط خواندنی سریعتر است.
۳ اشتباه رایج که باید ازشون پرهیز کنی:
- فراموش کردن SaveChanges بعد از Add/Update/Delete.
- استفاده از ToList روی کل جدول قبل از Where.
- لود نکردن دادههای مرتبط با Include و بعد دسترسی بهشون.
اگر فقط ۵ دقیقه وقت داری، اینها رو یاد بگیر:
- ساخت DbContext و DbSet.
- نوشتن یک کوئری ساده با LINQ.
- صدا زدن SaveChanges برای ذخیره.
۱. مقدمه
Entity Framework Core یا به اختصار EF Core یک ORM یا Object-Relational Mapper است. یعنی میتونی با دیتابیس به جای SQL مستقیم، با کلاسهای C# کار کنی.
این موضوع چیه؟
EF Core جدولهای دیتابیس رو به کلاسهای C# تبدیل میکنه. مثلاً جدول Products رو با کلاس Product و ستونهاش رو با Property ها نشون میده.چرا باید یادش بگیری؟
چون کار با دیتابیس رو خیلی سادهتر، خواناتر و قابل نگهداریتر میکنه. دیگه لازم نیست SQL خام بنویسی.کجا استفاده میشه؟
در برنامههای ASP.NET Core، API ها، برنامههای دسکتاپ و موبایل با داتنت. هر جایی که نیاز به دیتابیس داشته باشی.
۲. پیشنیازها
قبل از شروع بهتره اینها رو بدونی:
- زبان C#: حداقل با کلاسها، Property ها و لیستها آشنا باشی.
- LINQ مقدماتی: چون کوئریهای EF Core با LINQ نوشته میشن.
- مفاهیم دیتابیس: جدول، ستون، کلید اصلی و ارتباط بین جدولها.
ابزارهای لازم:
- .NET SDK نسخهی ۶ یا ۸
- Visual Studio یا VS Code
- SQLite یا SQL Server (برای شروع SQLite خیلی سادهتره)
۳. نصب و راهاندازی
گام ۱: ساخت پروژه
dotnet new console -n EfCoreBeginner
cd EfCoreBeginner
گام ۲: نصب پکیجهای EF Core
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet tool install --global dotnet-ef
Microsoft.EntityFrameworkCore.Sqliteبرای اتصال به دیتابیس SQLiteMicrosoft.EntityFrameworkCore.Designبرای استفاده از Migration هاdotnet-efابزار خط فرمان EF Core
گام ۳: ساخت اولین کلاس Entity
کلاس Product رو بساز:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
اینجا Id به صورت خودکار Primary Key در نظر گرفته میشه.
گام ۴: ساخت DbContext
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public DbSet<Product> Products => Set<Product>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=shop.db");
}
}
DbSet<Product>یعنی جدول ProductsUseSqliteآدرس فایل دیتابیس رو مشخص میکنه
گام ۵: ساخت Migration و دیتابیس
dotnet ef migrations add Init
dotnet ef database update
با این دو دستور، دیتابیس shop.db ساخته میشه.
۴. مفاهیم پایه
DbContext
DbContext مثل پل ارتباطی بین کد C# و دیتابیس عمل میکنه. همهی کوئریها و تغییرات از طریق اون انجام میشن.
using var db = new AppDbContext();
DbSet
هر DbSet<T> نماینده یک جدول در دیتابیس است. مثلاً db.Products یعنی جدول Products.
var allProducts = db.Products.ToList();
Entity
Entity همون کلاس C# است که به یک جدول مربوط میشه. Property های کلاس همون ستونهای جدول هستن.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
LINQ
کوئریها رو با LINQ مینویسی، نه SQL مستقیم:
var cheapProducts = db.Products
.Where(p => p.Price < 100000)
.OrderBy(p => p.Name)
.ToList();
SaveChanges
هر تغییری در Add، Update یا Delete فقط در حافظه انجام میشه. برای ذخیره در دیتابیس باید SaveChanges صدا بزنی.
db.SaveChanges();
۵. مثالهای کد ساده
Create — افزودن داده
using (var db = new AppDbContext())
{
db.Products.Add(new Product
{
Name = "دفتر",
Price = 50000
});
db.SaveChanges();
}
Read — خواندن داده
using (var db = new AppDbContext())
{
var cheapProducts = db.Products
.Where(p => p.Price < 100000)
.ToList();
foreach (var product in cheapProducts)
{
Console.WriteLine($"{product.Name} - {product.Price}");
}
}
Update — ویرایش داده
using (var db = new AppDbContext())
{
var product = db.Products.FirstOrDefault(p => p.Id == 1);
if (product != null)
{
product.Price = 150000;
db.SaveChanges();
}
}
Delete — حذف داده
using (var db = new AppDbContext())
{
var product = db.Products.Find(2);
if (product != null)
{
db.Products.Remove(product);
db.SaveChanges();
}
}
۶. مثال واقعی و کاربردی
یک برنامه کنسول کوچک برای مدیریت محصولات میسازیم.
گام ۱: ساخت Entity و DbContext
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=shop.db");
}
}
گام ۲: نوشتن منطق برنامه
class Program
{
static void Main()
{
using var db = new AppDbContext();
db.Database.EnsureCreated();
while (true)
{
Console.WriteLine("\n1. افزودن محصول");
Console.WriteLine("2. نمایش محصولات");
Console.WriteLine("3. خروج");
Console.Write("انتخاب: ");
var choice = Console.ReadLine();
if (choice == "1")
{
Console.Write("نام: ");
var name = Console.ReadLine();
Console.Write("قیمت: ");
var price = decimal.Parse(Console.ReadLine());
db.Products.Add(new Product
{
Name = name,
Price = price
});
db.SaveChanges();
Console.WriteLine("ثبت شد.");
}
else if (choice == "2")
{
var products = db.Products
.OrderBy(p => p.Price)
.ToList();
foreach (var p in products)
{
Console.WriteLine($"{p.Id} - {p.Name} - {p.Price}");
}
}
else if (choice == "3")
{
break;
}
}
}
}
اینجا از EnsureCreated برای سادگی استفاده کردیم، در پروژههای واقعی بهتره از Migration استفاده کنی.
۷. مباحث پیشرفته
ارتباط بین جداول
فرض کن هر محصول به یک دستهبندی تعلق داره:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public List<Product> Products { get; set; } = new();
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
برای لود کردن دادههای مرتبط:
var productsWithCategory = db.Products
.Include(p => p.Category)
.ToList();
AsNoTracking
برای کوئریهای فقط خواندنی:
var products = db.Products
.AsNoTracking()
.Where(p => p.Price > 100000)
.ToList();
این کار باعث میشه EF Core دادهها رو track نکنه و کوئری سریعتر اجرا بشه.
Index برای بهینهسازی جستجو
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasIndex(p => p.Name);
}
۸. اشتباهات رایج
فراموش کردن SaveChanges
بعد از Add یا Update حتماً بایدSaveChangesصدا بزنی.استفاده از ToList قبل از Where
db.Products.ToList().Where(...)همه رکوردها رو به حافظه میآره. همیشه اولWhereبعدToList.لود نکردن دادههای مرتبط
وقتی ازIncludeاستفاده نکنی، دادههای مرتبطnullیا خالی میمونن.استفاده از DbContext به صورت سراسری
DbContext باید کوتاهعمر باشه، نه اینکه یک نمونه برای کل برنامه ساخته بشه.تغییر دادن دادههای AsNoTracking
دادههایی که با AsNoTracking لود میشن track نمیشن و تغییراتشون ذخیره نمیشه.
۹. بهترین روشها (Best Practices)
- استفاده از Dependency Injection
در برنامههای ASP.NET Core:
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlite(builder.Configuration.GetConnectionString("Default")));
- استفاده از متدهای Async
برای برنامههای وب و API:
var products = await db.Products.ToListAsync();
await db.SaveChangesAsync();
- پروجکشن به جای لود کامل
var productNames = db.Products
.Where(p => p.Price > 100000)
.Select(p => p.Name)
.ToList();
- AsNoTracking برای دادههای فقط خواندنی
- استفاده از Migration به جای EnsureCreated در پروژه واقعی
- کوتاه نگه داشتن عمر DbContext
۱۰. منابع و ادامه مسیر
- مستندات رسمی EF Core
- مسیر یادگیری Microsoft Learn برای EF Core
- مخزن GitHub پروژه EF Core
- کتاب Entity Framework Core in Action برای یادگیری عمیقتر
- کانالهای یوتیوب مثل Nick Chapsas و IAmTimCorey برای آموزشهای کاربردی