عنوان:

‫استفاده از JSON در EF Core 8


نویسنده: محمد شریفی
تاریخ: ۱۴۰۴/۰۱/۰۲ ۰۷:۲۵
آدرس: www.dntips.ir
در نسخه EF Core 8، قابلیت پشتیبانی از JSON در پایگاه داده‌های SQL Server و PostgreSQL بهبود یافته است. این ویژگی امکان ذخیره‌سازی داده‌های پیچیده و سلسله‌مراتبی را در ستون‌های JSON فراهم می‌کند، بدون نیاز به نرمال‌سازی بیش‌ازحد جداول.
در این مقاله، نحوه استفاده از JSON در EF Core 8 را بررسی می‌کنیم.

۱. تعریف یک مدل با ویژگی JSON

فرض کنید می‌خواهیم اطلاعات آدرس یک کاربر را به‌صورت JSON در دیتابیس ذخیره کنیم.
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string City { get; set; }
    public string Street { get; set; }
    public string ZipCode { get; set; }
}

۲. تنظیم مدل در DbContext

برای اینکه Address به‌عنوان ستون JSON در دیتابیس ذخیره شود، باید در DbContext، آن را دارای مالک (Owned) تعریف کنیم:
public class AppDbContext : DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .OwnsOne(u => u.Address, a =>
            {
                a.ToJson();
            });
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("YourConnectionString");
    }
}

۳. ایجاد و مهاجرت دیتابیس

پس از تنظیم مدل، باید مهاجرت (Migration) را اجرا کنیم تا تغییرات در دیتابیس اعمال شوند:
dotnet ef migrations add AddJsonColumn
dotnet ef database update
در SQL Server، خروجی این دستور، یک ستون Address با نوع nvarchar(max) خواهد بود که داده‌های JSON را در خود نگه می‌دارد. در PostgreSQL، این ستون از نوع jsonb خواهد بود.

محدود کردن طول داده‌های JSON
در SQL Server، برای محدود کردن طول کلی داده‌های JSON در ستون Address به 500 کاراکتر، می‌توانید هر یک از فیلدهای Address را محدود کنید تا مجموع طول همه این فیلدها به 500 کاراکتر برسد. برای این کار از ویژگی HasMaxLength در EF Core استفاده می‌کنیم:
public class AppDbContext : DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .OwnsOne(u => u.Address, a =>
            {
                a.ToJson();
                a.Property(p => p.City).HasMaxLength(150);  
                a.Property(p => p.Street).HasMaxLength(150);
                a.Property(p => p.ZipCode).HasMaxLength(200);
            });
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("YourConnectionString");
    }
}

در اینجا، طول فیلدهای City، Street و ZipCode به‌طور جداگانه محدود شده‌اند، به طوری که مجموع طول آنها به 500 کاراکتر می‌رسد.
خروجی جدول در SQL Server به صورت زیر خواهد بود:
CREATE TABLE [Users] (
    [Id] INT NOT NULL PRIMARY KEY,
    [Name] NVARCHAR(100),
    [Address] NVARCHAR(500) 
);
در PostgreSQL، محدودیت طول برای داده‌های JSON به طور مستقیم قابل اعمال نیست، بنابراین باید داده‌ها را قبل از ذخیره در برنامه محدود کنید. ستون Address همچنان از نوع jsonb باقی می‌ماند:
CREATE TABLE "Users" (
    "Id" SERIAL PRIMARY KEY,
    "Name" VARCHAR(100),
    "Address" JSONB
);
در اینجا، باید در سطح کد برنامه، طول داده‌های فیلدهای City، Street و ZipCode را به‌گونه‌ای محدود کنید که مجموع طول این فیلدها به 500 کاراکتر برسد.

۴. درج داده در ستون JSON

می‌توانیم یک کاربر جدید را همراه با آدرس در دیتابیس ذخیره کنیم:
using var context = new AppDbContext();

var user = new User
{
    Name = "Mohammad",
    Address = new Address
    {
        City = "Tehran",
        Street = "Street 1",
        ZipCode = "1234567890"
    }
};

context.Users.Add(user);
context.SaveChanges();

۵. فیلتر و جستجو در داده‌های JSON

در EF Core 8، می‌توان به‌صورت مستقیم روی فیلدهای JSON جستجو انجام داد:
var usersInTehran = context.Users
    .Where(u => u.Address.City == "Tehran")
    .ToList();
این کوئری در SQL Server معادل زیر است:
SELECT * FROM Users WHERE JSON_VALUE(Address, '$.City') = 'Tehran'
در PostgreSQL نیز به‌شکل زیر اجرا می‌شود:
SELECT * FROM Users WHERE Address->>'City' = 'Tehran';

۶. به‌روزرسانی مقدار JSON در EF Core 8

در EF Core 8، می‌توان فیلدهای خاصی از JSON را بدون لود کامل داده، به‌روزرسانی کرد:
var user = context.Users.First();
user.Address.City = "Esfahan";
context.SaveChanges();

۷. مزایای استفاده از JSON در EF Core 8

۱- کاهش تعداد جداول و ارتباطات پیچیده در دیتابیس
۲- بهبود کارایی خواندن و نوشتن داده‌ها
۳- قابلیت ذخیره داده‌های نیمه‌ساختاریافته
البته JSON برای همه سناریوها مناسب نیست و در برخی موارد، همچنان نرمال‌سازی دیتابیس انتخاب بهتری خواهد بود.

۸. مقایسه JSON و ذخیره‌سازی داده‌های SQL سنتی
برای بعضی از سناریوها، استفاده از JSON در پایگاه داده می‌تواند مزایای فوق را به همراه داشته باشد، اما در شرایطی که داده‌ها نیاز به جستجو و فیلتر دقیق دارند، استفاده از نرمال‌سازی داده‌ها (جدا کردن جداول) ممکن است بهینه‌تر باشد.

مثلاً اگر بخواهید فیلدهای خاص از داده‌های JSON را زیاد جستجو کنید یا به‌طور مکرر با آنها کار کنید، ممکن است نرمال‌سازی جداول به‌طور مستقیم یا ایجاد ایندکس‌های ویژه برای ستون‌های خاصی از JSON در دیتابیس مفیدتر باشد.

جمع‌بندی

EF Core 8 پشتیبانی از JSON را بهبود بخشیده و امکان ذخیره، جستجو و به‌روزرسانی داده‌های JSON را در SQL Server و PostgreSQL فراهم کرده است. استفاده از این قابلیت می‌تواند مدیریت داده‌های پیچیده را ساده‌تر کند، به‌ویژه زمانی که نیاز به ذخیره اطلاعات سلسله‌مراتبی یا انعطاف‌پذیر داریم. با این حال، باید همواره در نظر داشت که استفاده از JSON برای تمامی سناریوها مناسب نیست و انتخاب مناسب‌ترین روش باید بر اساس نیازهای پروژه صورت گیرد.