در این مقاله قصد دارم نحوه شخصی سازی روابط چند به چند در EF Code First را برای شما شرح دهم. بعد از خواندن مقاله می توانید روابط چند به چند با فیلد اضافه ساخته و از آن استفاده کنید.

اگر با Entity Framework Code First آشنایی داشته باشید، میدانید که برای پیاده سازی روابط چند به چند کافی است در طرفین رابطه، Navigation Property هایی از نوعی Collection (مثلا لیست) از طرف مقابل قرار دهیم. به مثال زیر توجه کنید:


public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual IList<Course> Courses { get; set; }
    }

public class Course
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual IList<Student> Students { get; set; }
    }

public class MyContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
    }

در این سناریو هر دانش آموز میتواند لیستی از دروس را اخذ کند و هر درس نیز توسط تعدادی دانش آموز اخد می شود. Entity Framework به صورت خودکار این رابطه چند به چند را به دو رابطه یک به چند تبدیل می کند. سپس جداول را میسازد. بعد از فعال سازی و ساخت Migration و اجرای دستور Update-Database جداول مربوط به کلاس های بالا به شکل زیر ساخته خواهند شد:

نمودار رابطه چند به چند

حال، فرض کنید بخواهیم تاریخ اخذ و نمره نهایی را نیز ذخیره کنیم. در این صورت اگر بخواهیم پایگاه داده استانداردی داشته باشیم باید ستون های تاریخ اخذ و نمره نهایی را به جدول StudentCourses اضافه کنیم.

چگونه روابط چند به چند را شخصی سازی کنیم؟

به صورت پیشفرض راه استانداردی با استفاده از Fluent Api و Annotations برای افزودن ستون به این جدول وجود ندارد. چرا که به صورت خودکار توسط EF ساخته می شود. اما راه حل چیست؟ می توان کلاس مربوط به جدول StudentCourses را به صورت دستی ایجاد و فیلد های تاریخ اخذ و نمره نهایی را به آن اضافه کرد. در واقع کار شکستن رابطه چند به چند و تبدیل آن به دو رابطه یک به چند را نیز خودمان انجام می دهیم. به مثال زیر که در ادامه مثال ابتدای مقاله است توجه کنید:


public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual IList<StudentCourse> StudentCourses { get; set; }
    }

    public class Course
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual IList<StudentCourse> StudentCourses { get; set; }
    }

    public class StudentCourse
    {
        [Key, Column(Order = 0)]
        public int StudentId { get; set; }

        [Key, Column(Order = 1)]
        public int CourseId { get; set; }

        public virtual Student Student { get; set; }
        public virtual Course Course { get; set; }

        public double Grade { get; set; }
        public DateTime DateTime { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
        public DbSet<StudentCourse> StudentCourses { get; set; }
    }

کلاس StudentCourse را ایجاد و به MyContext اضافه می کنیم. به تغییرات کلاس های Student و Course نیز توجه کنید.

توجه:  اگر از ابتدا کلاس StudentCourse را نسازید و Entity Framework این جدول را برای شما بسازد، سپس این کلاس را ساخته و Migration ایجاد کنید، Entity Framework جدول قبلی را حذف می کند و برای کلاس StudentCourse جدول جدیدی میسازد. پس بهتر است قبل از ساخت Migration برای رابطه چند به چند در صورت نیاز این رابطه را بشکنید و کلاس سوم با فیلد های اضافه را ایجاد و سپس Migration انجام دهید. البته ممکن است در صورت همنام قرار دادن نام جدول و ستون ها با استفاده از Annotations یا Fluent Api بتوان از حذف جدول فعلی و ساخت جدول جدید جلوگیری کرد.

جداول به شکل زیر تغییر کرد:

شخصی سازی رابطه چند به چندبرای استفاده از کلاس های بالا به مثال زیر توجه کنید:

 


var context = new MyContext();

            var student = new Student()
            {
                Name = "Sara"
            };
            context.Students.Add(student);

            var course1 = new Course()
            {
                Name = "Java"
            };
            var course2 = new Course()
            {
                Name = "C#"
            };
            context.Courses.Add(course1);
            context.Courses.Add(course2);

            context.SaveChanges();


            var studentCourse1 = new StudentCourse()
            {
                StudentId = student.Id,
                CourseId = course1.Id,
                Grade = 18.5,
                DateTime = DateTime.Now
            };
            context.StudentCourses.Add(studentCourse1);


            var studentCourse2 = new StudentCourse()
            {
                StudentId = student.Id,
                CourseId = course2.Id,
                Grade = 17,
                DateTime = DateTime.Now
            };
            context.StudentCourses.Add(studentCourse1);

            context.SaveChanges();