رابطه یا Relation
به طور کلی وقتی در یک سیستم بانک اطلاعاتی یک موجودیت با یک موجودیت دیگر ارتباط داشته باشد، به آن رابطه یا Relation می گویند. برای مثال، در یک سیستم مدیریت فروش، یک موجودیت مشتری می تواند داخل سیستم چندین سفارش ثبت شده داشته باشد. یعنی در سیستم ما، بین موجودیت مشتری و موجودیت سفارش رابطه وجود دارد.
انواع رابطه
به طور کلی رابطه ها به سه دسته تقسیم می شوند:
- رابطه One-To-Many
- رابطه Many-To-Many
- رابطه One-To-One
رابطه One-To-Many
این نوع رابطه که رابطه یک به چند نیز نامیده می شود به این معنی می باشد که یک نمونه از یک موجودیت می تواند با چندین نمونه از یک موجودیت دیگر ارتباط داشته باشد. اگر به مثال مشتری و سفارش برگردیم، گفتیم که یک مشتری می تواند داخل سیستم چندین سفارش ثبت شده داشته باشد و هر سفارش متعلق به یک مشتری است. در حقیقت رابطه بین مشتری و سفارش یک رابطه یک به چند است.
رابطه Many-To-Many
این رابطه که رابطه چند به چند نیز نامیده می شود، تعیین می کند که یک نمونه از یک موجودیت می تواند با چندین نمونه از موجودیت دیگر ارتباط داشته باشد و بالعکس. برای مثال، در یک سیستم ما تعدادی کاربر و تعدادی گروه های کاربری داریم. هر گروه کاربری می تواند چندین کاربر داشته باشد و هر کاربر می تواند عضو چندین گروه کاربری باشد. در حقیقت رابطه بین گروه کاربری و کاربر، رابطه از نوع چند به چند است.
رابطه One-To-One
این رابطه که رابطه یک به یک نیز نامیده می شود، تعیین می کند یک نمونه از یک موجودیت تنها می تواند با یک نمونه از موجودیت دیگر ارتباط داشته باشد و بالعکس. برای مثال در یک سیستم، ما یک کاربر و یک پروفایل کاربری داریم، هر کاربر متعلق به یک پروفایل و هر پروفایل متعلق به یک کاربر می باشد، یعنی یک کاربر نمی تواند چندین پروفایل داشته باشد. در این مورد، رابطه بین کاربر و پروفایل رابطه از نوع یک به یک است.
در ادامه به نحوه پیاده سازی این رابطه ها با استفاده از روش FluentAPI در Entity Framework Core و همچنین نحوه تعریف جداول بانک اطلاعاتی خواهیم پرداخت.
Has/With pattern
هنگام پیکربندی روابط بین Entityها با Fluent API، از الگوی Has / With استفاده خواهید کرد. قسمت Has این الگو با متدهای HasOne و HasMany نشان داده شده است. قسمت With این الگو با متدهای WithOne و WithMany نمایش داده می شود.
Configuring One To One Relationships In Entity Framework Core
Entity Framework Core با قادر بودن شناسایی پراپرتی foreign key، رابطه یک به یک را پیکربندی می کند و از این طریق نهاد اصلی (Principal entity) و نهاد وابسته (Dependent entity) در رابطه را مشخص می کند. اگر Entity Framework Core قادر به انجام این کار نباشد، یا به این دلیل است که نام پراپرتی foreign key از قرارداد پیروی نمی کند، یا اینکه در مدل گنجانده نشده است و درنتیجه هنگام تلاش برای ایجاد یک مهاجرت، پیام خطایی ایجاد می شود.
بنابراین درصورتی که قصد دارید Entity Framework Core بر اساس convention خود رابطه یک به یک را پیکربندی نماید، باید foreign key را در طرف نهاد وابسته مشخص کنید و نام پراپرتی foreign key را مطابق با Convention انتخاب نمایید تا Entity Framework Core قادر به شناسایی آن در Model باشد. در مدل زیر پراپرتی کلید خارجی AuthorRef در موجودیت AuthorBiography قرارداد نام گذاری foreign key را پیروی نکرده است:
در نتیجه، EF Core قادر به شناسایی نهاد وابسته در رابطه نخواهد بود. با استفاده از Fluent API رابطه یک به یک بین Author و AuthorBiography را مانند شکل زیر پیکربندی می کنیم:
Configure One to Many Relationships using Fluent API in Entity Framework Core
شما در مورد Convention های روابط یک به چند یاد گرفتید. بیشتر روابط یک به چند (One to Many) در Entity Framework Core از قراردادها پیروی می کنند و نیازی به تنظیمات اضافی ندارند. جایی که Model از قراردادها پیروی نمی کند، Fluent API می تواند برای پیکربندی صحیح رابطه بین Entityها استفاده شود.
Model زیر شرکت ها و کارمندان دارای Reverse navigation property را تعریف می کند که در نهاد وابسته (Employee) تعریف شده است، اما هیچ پراپرتی foreign key در نهاد وابسته ندارد:
یک شرکت تعداد کارمندان زیادی دارد که هر کدام یک شرکت دارند. این رابطه به شرح زیر است:
این پیکربندی همچنین می تواند با طرف دیگر رابطه شروع شود:
این پیکربندی چه از طریق Company یا چه از طریق Employee شروع شود، به یک رابطه اختیاری منجر می شود. یک پراپرتی foreign key در سایه به نام CompanyId توسط EF Core به نهاد Employee اضافه می شود که Nullable خواهد بود.
در تصاویر زیر جداول ساخته شده توسط SQL Server برای هر کدام از Entityهای Company و Employee را می بینید:
Required relationship
برای جلوگیری از اختیاری بودن رابطه می توانید از متد IsRequired در رابطه استفاده کنید:
بعد از افزودن متد IsRequired() به پیکربندی، جداول ساخته شده توسط SQL Server برای Entityهای Company و Employee به شکل زیر خواهد بود:
اگر رابطه به صورت اختیاری تنظیم شده باشد، رفتار پیش فرض EF Core این است که در صورت حذف نهاد اصلی، هیچگونه اقدامی در رابطه با نهاد وابسته انجام ندهد. در نتیجه، اگر نهاد اصلی را حذف کنید، کلید خارجی در نهاد وابسته که می بایست به یک رکورد از نهاد اصلی اشاره کند، null می گردد. رفتار پیش فرض یک دیتابیس در این سناریو ایجاد خطا است: مقادیر کلیدهای خارجی نهاد وابسته (dependent entity) باید به مقادیر کلید اصلی نهاد اصلی (principal entity) مراجعه کنند.
شما می توانید با استفاده از متد OnDelete این رفتار را تغییر دهید. مثال زیر مقدار کلید خارجی نهاد وابسته را در صورت حذف نهاد اصلی null می کند:
از متد OnDelete برای مشخص کردن عملی که باید در یک رابطه وابسته هنگام حذف نهاد اصلی انجام گیرد استفاده می شود. متد OnDelete یک پارامتر DeleteBehavior را دریافت می کند:
Cascade - وابستگان باید حذف شوند.
Restrict - وابستگان بی تأثیر هستند.
SetNull - مقادیر کلید خارجی در سطرهای وابسته به NULL تغییر می یابد.
اگر پایگاه داده از طریق مهاجرت های EF Core ایجاد شده باشد، رفتار مشخص شده بطور خودکار تنظیم می شود.
Configure Many-to-Many Relationships in Entity Framework Core
در اینجا شما یاد می گیرید که چگونه پیکربندی رابطه Many-to-Many دو Entity با استفاده از Fluent API در Entity Framework Core را انجام دهید.
در ابتدا یک رابطه Many-to-Many بین افراد دانشجو و دوره ایجاد می کنیم، جایی که یک دانشجو می تواند بسیاری از دوره ها را ثبت نام کند و به همین ترتیب، بسیاری از دانشجویان می توانند به یک دوره بپیوندند.
رابطه Many-to-Many در بانک اطلاعاتی با استفاده از یک جدول واسط نمایش داده می شود که شامل کلیدهای خارجی هر دو جدول است. همچنین، این کلیدهای خارجی composite primary keys هستند.
نکته: هیچ قرارداد پیش فرضی در Entity Framework Core وجود ندارد که بطور خودکار یک رابطه Many-to-Many را پیکربندی کند. شما باید آن را با استفاده از Fluent API پیکربندی کنید.
قبل از هر چیز، همانطور که در زیر نشان داده شده است، StudentCourse را تعریف کنید.
کلاس StudentCourse بالا شامل navigation property های Student و Course و همچنین foreign key های StudentId و CourseId است که از قرارداد پیروی می کنند.
اکنون ما نیازمند ایجاد دو رابطه One-to-Many مجزا بین Course با StudentCourse و Student با StudentCourse هستیم. ما می توانیم این کار را فقط با پیروی از قرارداد رابطه One-to-Many انجام دهیم، همانطور که در زیر آمده است.
حال، کلیدهای خارجی در جدول واسط (StudentCourse) باید Composite Primary Key باشند. این کار فقط می تواند با استفاده از Fluent API تنظیم شود ، مانند شکل زیر.
در کد بالا دستور
modelBuilder.Entity<StudentCourse>().HasKey(sc => new { sc.StudentId, sc.CourseId });
StudentId و CourseId را به عنوان Composite key پیکربندی می کند.
اگر Entityها از قراردادهای رابطه One-to-Many پیروی کنند، شما می توانید به روش بالا رابطه Many-to-Many را پیکربندی کنید. فرض کنید که نام کلیدهای خارجی از قرارداد پیروی نمی کنند ( به عنوان مثال SID به جای StudentId و CID به جای CourseId) در این صورت می توانید آن را با استفاده از Fluent API به شکل زیر پیکربندی کنید.