آموزش Entity Framework Core

آموزش Entity framework core مبتدی
parsakarimidev.ir

آموزش Entity Framework Core

آموزش Entity framework coreفریم‌ورک سطح: مبتدی 1405/07/03

آموزش Entity Framework Core

⚡ خلاصه سریع — اصل کاری‌ها

این‌ها مهم‌ترین چیزهایی هستن که اگه هیچی ندونی، فقط اینا رو بدونی کافیه:

  • نکته ۱: EF Core یک ORM است که جدول‌های دیتابیس رو به کلاس‌های C# تبدیل می‌کنه.
  • نکته ۲: DbContext نقطه اصلی اتصال به دیتابیس است.
  • نکته ۳: DbSet نماینده یک جدول در دیتابیس است.
  • نکته ۴: با LINQ کوئری می‌نویسی، نه SQL مستقیم.
  • نکته ۵: برای ذخیره تغییرات همیشه SaveChanges() رو صدا کن.
  • نکته ۶: Migration ساختار دیتابیس رو می‌سازه و تغییر می‌ده.
  • نکته ۷: Include باعث لود داده‌های مرتبط می‌شود.
  • نکته ۸: AsNoTracking برای کوئری‌های فقط خواندنی سریع‌تر است.

۳ اشتباه رایج که باید ازشون پرهیز کنی:

  1. فراموش کردن SaveChanges بعد از Add/Update/Delete.
  2. استفاده از ToList روی کل جدول قبل از Where.
  3. لود نکردن داده‌های مرتبط با Include و بعد دسترسی بهشون.

اگر فقط ۵ دقیقه وقت داری، این‌ها رو یاد بگیر:

  1. ساخت DbContext و DbSet.
  2. نوشتن یک کوئری ساده با LINQ.
  3. صدا زدن 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 برای اتصال به دیتابیس SQLite
  • Microsoft.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> یعنی جدول Products
  • UseSqlite آدرس فایل دیتابیس رو مشخص می‌کنه

گام ۵: ساخت 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);
}

۸. اشتباهات رایج

  1. فراموش کردن SaveChanges
    بعد از Add یا Update حتماً باید SaveChanges صدا بزنی.

  2. استفاده از ToList قبل از Where
    db.Products.ToList().Where(...) همه رکوردها رو به حافظه می‌آره. همیشه اول Where بعد ToList.

  3. لود نکردن داده‌های مرتبط
    وقتی از Include استفاده نکنی، داده‌های مرتبط null یا خالی می‌مونن.

  4. استفاده از DbContext به صورت سراسری
    DbContext باید کوتاه‌عمر باشه، نه اینکه یک نمونه برای کل برنامه ساخته بشه.

  5. تغییر دادن داده‌های 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

۱۰. منابع و ادامه مسیر

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.