EF Code-First - Thuộc tính InverseProperty

Thuộc tính InverseProperty trong Entity Framework

Thuộc tính InverseProperty (InverseProperty Attribute) được sử dụng khi hai thực thể có nhiều hơn một mối quan hệ. Để hiểu thuộc tính InverseProperty, hãy xem ví dụ thực thể CourseTeacher sau đây.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    public ICollection<Course> OnlineCourses { get; set; }
}

Trong ví dụ trên, các thực thể CourseTeacher có mối quan hệ một-nhiều trong đó một giáo viên có thể dạy nhiều khóa học khác nhau.

Theo các quy ước mặc định trong EF 6 và EF Core, ví dụ trên sẽ tạo các bảng sau trong cơ sở dữ liệu.

inverseproperty example

Bây giờ, giả sử chúng ta thêm một mối quan hệ một-nhiều giữa các thực thể TeacherCourse như sau.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    public ICollection<Course> OnlineCourses { get; set; }
    public ICollection<Course> ClassRoomCourses { get; set; }
}

Trong ví dụ trên, các thực thể CourseTeacher có hai mối quan hệ một-nhiều. Một khóa học có thể được dạy bởi một giáo viên trực tuyến hoặc một giáo viên trên lớp.

Theo cùng cách trên, một giáo viên cũng có thể dạy nhiều khóa học trực tuyến hoặc nhiều khóa học trên lớp.

Ở trường hợp này, EF API không thể xác định đầu kia của mối quan hệ. Nó sẽ đưa ra ngoại lệ sau đây cho ví dụ trên trong quá trình migration.

Không thể xác định mối quan hệ bởi thuộc tính  'Course.OnlineTeacher' thuộc loại 'Teacher'. Hoặc là cấu hình mối quan hệ bằng cách thủ công hoặc bỏ qua thuộc tính này bằng cách sử dụng thuộc tính '[NotMapped]' hoặc bằng cách sử dụng 'EntityTypeBuilder.Ignore' trong 'OnModelCreating'.

Tuy nhiên, EF 6 sẽ tạo bảng Courses sau với bốn khóa ngoại như sau:

inverseproperty example

Để giải quyết vấn đề này, sử dụng thuộc tính InverseProperty để định cấu hình đầu kia của mối quan hệ như dưới đây.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    [InverseProperty("OnlineTeacher")]
    public ICollection<Course> OnlineCourses { get; set; }
    [InverseProperty("ClassRoomTeacher")]
    public ICollection<Course> ClassRoomCourses { get; set; }
}

Trong ví dụ trên, thuộc tính InverseProperty được áp dụng trên hai thuộc tính điều hướng OnlineCoursesClassRoomCourses để chỉ định thuộc tính điều hướng liên quan của chúng trong thực thể Course.

Vì vậy, bây giờ EF có thể tìm ra tên khóa ngoại tương ứng. EF 6 tạo khóa ngoại OnlineTeacher_TeacherIdClassRoomTeacher_TeacherId cho bảng Courses như sau:

inverseproperty example

Bạn có thể sử dụng thuộc tính ForeignKey để cấu hình tên khóa ngoại như bên dưới.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    [ForeignKey("OnlineTeacher")]
    public int? OnlineTeacherId { get; set; }
    public Teacher OnlineTeacher { get; set; }

    [ForeignKey("ClassRoomTeacher")]
    public int? ClassRoomTeacherId { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    [InverseProperty("OnlineTeacher")]
    public ICollection<Course> OnlineCourses { get; set; }
    [InverseProperty("ClassRoomTeacher")]
    public ICollection<Course> ClassRoomCourses { get; set; }
}

Ví dụ trên sẽ dẫn đến các bảng sau trong cơ sở dữ liệu.

inverseproperty example

Do đó, bạn có thể sử dụng các thuộc tính InversePropertyForeignKey để cấu hình nhiều mối quan hệ trên cùng các thực thể.