در این مقاله جامع، به بررسی دقیق این مفهوم، نحوه کارکرد، مزایا، محدودیتها و مثالهای عملی آن خواهیم پرداخت.
در دنیای برنامهنویسی شیءگرا و مدلسازی داده، ما معمولاً با دو نوع شیء روبرو هستیم:
Entities (موجودیتها): اشیائی که دارای یک هویت (Identity) منحصربهفرد (مانند ID) هستند و در طول زمان، حتی اگر ویژگیهایشان تغییر کند، هویتشان ثابت میماند (مثل یک «کاربر»).
Owned Entities (موجودیتهای تحت مالکیت): اشیائی که به خودی خود هویتی ندارند و تعریف آنها وابسته به موجودیت دیگری است که مالک (Owner) آنها محسوب میشود.
به زبان ساده، یک Owned Entity موجودیتی است که فاقد کلید اصلی (Primary Key) مستقل در مدل دامنه است و تنها به عنوان بخشی از یک موجودیت دیگر معنا پیدا میکند.
تصور کنید سیستمی دارید که اطلاعات کاربران را ذخیره میکند. هر کاربر یک «آدرس» دارد. آدرس شامل فیلدهایی مثل خیابان، شهر و کد پستی است.
دو راه برای مدلسازی این آدرس وجود دارد:
روش سنتی: تمام فیلدهای آدرس را مستقیماً در کلاس User قرار دهید. این کار باعث شلوغی کلاس کاربر میشود و اصل Single Responsibility را نقض میکند.
روش Owned Entity: یک کلاس جداگانه به نام Address بسازید و آن را در کلاس User استفاده کنید.
برای تعریف این موجودیتها، ما از Fluent API در متد OnModelCreating استفاده میکنیم.
الف) استفاده از OwnsOne (رابطه یکبهیک)
این حالت زمانی استفاده میشود که مالک، تنها یک نمونه از موجودیت تحت مالکیت را داشته باشد (مثل یک کاربر و یک آدرس).
در تنظیمات DbContext:
نحوه ذخیرهسازی در دیتابیس: به طور پیشفرض، EF Core فیلدهای Address را در همان جدول Users تخت (Flatten) میکند. یعنی جدول کاربران دارای ستونهای Id ، Name ، HomeAddress_Street و HomeAddress_City خواهد بود.
ب) استفاده از OwnsMany (رابطه یکبه-چند)
از نسخه EF Core 2.2 به بعد، امکان تعریف مجموعهای از موجودیتهای تحت مالکیت فراهم شد. مثلاً یک کاربر میتواند چندین «شماره تماس» داشته باشد که هویت مستقل ندارند.
در این حالت، EF Core به صورت خودکار یک جدول جداگانه برای شمارهها ایجاد میکند، اما همچنان از نظر منطقی آنها را تحت مالکیت کاربر میداند.
یکی از قدرتهای Owned Entities در نحوه ذخیرهسازی آنهاست:
Table Splitting (جداسازی در یک جدول): همانطور که گفته شد، فیلدها در جدول اصلی ادغام میشوند. این کار باعث بهبود کارایی در خواندن دادهها میشود (نیاز به JOIN نیست).
Separate Table (جدول جداگانه): اگر بخواهید فیلدهای Owned Entity را در جدول دیگری ذخیره کنید (بدون اینکه آن را تبدیل به یک موجودیت مستقل کنید)، میتوانید از متد ToTable استفاده کنید:
کد تمیزتر (Clean Code): منطقهای مرتبط (مثل اعتبارسنجی آدرس یا محاسبات پولی) در کلاس خودشان قرار میگیرند.
Encapsulation: میتوانید متدهایی را درون کلاس تحت مالکیت بنویسید که فقط روی دادههای خودش کار کند.
استفاده مجدد (Reusability): میتوانید کلاس Address را در موجودیتهای دیگر مثل Store یا Supplier هم به کار ببرید (البته هر کدام کپی خود را در دیتابیس خواهند داشت).
بهبود عملکرد در پرسوجوها: به دلیل ادغام در جدول اصلی (در حالت OwnsOne)، بارگذاری دادهها سریعتر انجام میشود.
با وجود مزایای زیاد، باید به نکات زیر توجه کرد:
عدم اشتراکگذاری: یک نمونه از Address نمیتواند همزمان متعلق به دو کاربر باشد. اگر آدرس را به کاربر دوم اختصاص دهید، یک کپی از آن ایجاد میشود.
پیچیدگی در Nullability: اگر تمام فیلدهای یک Owned Entity در دیتابیس null باشند، EF Core هنگام واکشی، کل آن شیء را null برمیگرداند.
محدودیت در ارثبری: Owned Entityها به خوبی از وراثت پشتیبانی نمیکنند.
چه زمانی باید از Owned Entities استفاده کنیم؟
اطلاعات مکانی: آدرس، مختصات جغرافیایی (طول و عرض جغرافیایی).
واحدهای پولی (Money Object): کلاسی که هم مبلغ و هم واحد پول (دلار، تومان) را در خود نگه میدارد.
زمانبندی: یک بازه زمانی شامل StartDate و EndDate.
Audit Logs: فیلدهایی مثل CreatedAt و CreatedBy که در تمام جداول تکرار میشوند.
موجودیتهای تحت مالکیت (Owned Entities) در EF Core ابزاری قدرتمند برای مدلسازی بهتر دادهها هستند. این ابزار به توسعهدهندگان اجازه میدهد تا کدی مطابق با اصول DDD و Clean Code بنویسند، بدون اینکه نیاز به ایجاد جداول اضافی یا کلیدهای خارجی پیچیده داشته باشند.
با استفاده از OwnsOne و OwnsMany میتوانید پیچیدگیهای دیتابیس را پنهان کرده و بر روی منطق تجاری تمرکز کنید.
0 نظر
هنوز نظری برای این مقاله ثبت نشده است.