EF Code-First - Cấu hình mối quan hệ một-nhiều
Cấu hình mối quan hệ một-nhiều trong Entity Framework
Ở phần này, chúng ta sẽ tìm hiểu cách cấu hình mối quan hệ một-nhiều giữa hai thực thể trong Entity Framework 6.x bằng cách sử dụng phương pháp tiếp cận Code First.
Chúng ta sẽ cấu hình mối quan hệ một-nhiều giữa các thực thể Student
và Grade
- một lớp có nhiều sinh viên.
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
}
Sau khi thực thi mối quan hệ một-nhiều trong các thực thể trên, các bảng cơ sở dữ liệu cho Student và Grade sẽ giống như bên dưới.
Các quy ước cho mối quan hệ một-nhiều
Có một số quy ước nhất định trong Entity Framework mà nếu các lớp thực thể tuân theo sẽ tự động dẫn đến mối quan hệ một-nhiều giữa hai bảng trong cơ sở dữ liệu. Bạn không cần phải cấu hình bất cứ điều gì khác.
Hãy xem một ví dụ về các quy ước tạo ra mối quan hệ một-nhiều trong Entity Framework Code First.
Quy ước 1:
Chúng tôi muốn thiết lập mối quan hệ một-nhiều giữa các thực thể Student
và Grade
. Có nghĩa là mỗi thực thể Student
sẽ trỏ đến một thực thể Grade
.
Điều này có thể thực hiện bằng cách tạo một thuộc tính điều hướng tham chiếu kiểu Grade
trong lớp thực thể Student
, như ví dụ bên dưới.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Grade Grade { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
}
Trong ví dụ trên, lớp Student
có một thuộc tính điều hướng tham chiếu của lớp Grade
. Vì vậy, có thể có nhiều học sinh trong một lớp.
Điều này sẽ dẫn đến mối quan hệ một-nhiều giữa bảng Students
và bảng Grades
trong cơ sở dữ liệu, trong đó bảng Students
có khóa ngoại Grade_GradeId
như hình bên dưới.
Lưu ý rằng thuộc tính tham chiếu là nullable, vì vậy nó tạo ra một cột khóa ngoại Grade_GradeId
có thể null trong bảng Students
.
Quy ước 2:
Có một thuộc tính điều hướng kiểu tập hợp trong thực thể chính như dưới đây.
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public ICollection<Student> Students { get; set; }
}
Trong ví dụ trên, thực thể Grade
có một thuộc tính điều hướng tập hợp kiểu ICollection<Student>
.
Điều này cũng dẫn đến mối quan hệ một-nhiều giữa các thực thể Student
và Grade
. Ví dụ này tạo ra kết quả tương tự trong cơ sở dữ liệu như quy ước 1.
Quy ước 3:
Có các thuộc tính điều hướng ở cả hai đầu cũng sẽ dẫn đến mối quan hệ một-nhiều, như được trình bày bên dưới.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Grade Grade { get; set; }
}
public class Grade
{
public int GradeID { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public ICollection<Student> Student { get; set; }
}
Trong ví dụ trên, lớp thực thể Student
có một thuộc tính điều hướng tham chiếu kiểu Grade
và lớp thực thể Grade
có một thuộc tính điều hướng tập hợp kiểu ICollection<Student>
dẫn đến mối quan hệ một-nhiều. Ví dụ này tạo ra kết quả tương tự trong cơ sở dữ liệu như quy ước 1.
Quy ước 4:
Một mối quan hệ được chỉ định đầy đủ ở cả hai đầu sẽ tạo ra mối quan hệ một-nhiều, như hình dưới đây.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int GradeId { get; set; }
public Grade Grade { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public ICollection<Student> Student { get; set; }
}
Trong ví dụ trên, lớp thực thể Student
có thuộc tính khóa ngoại GradeId
và thuộc tính tham chiếu của nó là Grade
. Điều này sẽ tạo mối quan hệ một-nhiều với cột khóa ngoại NotNull trong bảng Students
, như được hiển thị bên dưới.
Nếu kiểu dữ liệu của GradeId
là số nguyên nullable, thì nó sẽ tạo khóa ngoại null.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int? GradeId { get; set; }
public Grade Grade { get; set; }
}
Đoạn mã trên sẽ tạo một cột GradeId
có thể null trong cơ sở dữ liệu vì chúng tôi đã sử dụng kiểu Nullable<int>
(int?
là viết tắt của Nullable<int>
)
Cấu hình mối quan hệ một-nhiều bằng Fluent API
Nói chung, bạn không cần định cấu hình mối quan hệ một-nhiều trong Entity Framework vì các quy ước ở trên sẽ giúp bạn làm điều này.
Tuy nhiên, bạn có thể định cấu hình các mối quan hệ bằng Fluent API tại một nơi để làm cho nó dễ bảo trì hơn.
Hãy xem các lớp thực thể Student
và Grade
sau.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int CurrentGradeId { get; set; }
public Grade CurrentGrade { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public ICollection<Student> Students { get; set; }
}
Bạn có thể cấu hình mối quan hệ một-nhiều cho các thực thể ở trên bằng Fluent API bằng cách ghi đè phương thức OnModelCreating
trong lớp Context, như ví dụ bên dưới.
public class SchoolContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Grade> Grades { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// configures one-to-many relationship
modelBuilder.Entity<Student>()
.HasRequired<Grade>(s => s.CurrentGrade)
.WithMany(g => g.Students)
.HasForeignKey<int>(s => s.CurrentGradeId);
}
}
Chúng ta hãy hiểu mã trên từng bước.
- Đầu tiên chúng ta cần chỉ định cấu hình cho lớp thực thể nào bằng khai báo
modelBuilder.Entity<student>()
- cấu hình cho thực thểStudent
. - Khai báo
.HasRequired<Grade>(s => s.CurrentGrade)
chỉ định rằng lớp thực thểStudent
yêu cầu thuộc tínhCurrentGrade
. Điều này sẽ tạo một cột khóa ngoài NotNull trong DB. - Khai báo
.WithMany(g => g.Students)
chỉ định rằng lớp thực thểGrade
có nhiều thực thểStudent
. - Bây giờ, nếu thực thể
Student
không tuân theo quy ước thuộc tính Id cho khóa ngoại, thì chúng ta có thể chỉ định tên của khóa ngoại bằng phương thứcHasForeignKey
. Khai báo.HasForeignKey<int>(s => s.CurrentGradeId)
chỉ định thuộc tính khóa ngoại trong thực thểStudent
.
Ngoài ra, bạn cũng có thể cấu hình mối quan hệ bắt đầu với thực thể Grade
thay vì thực thể Student
như ở ví dụ trên. Ví dụ sau đây tạo ra kết quả tương tự như trên.
modelBuilder.Entity<Grade>()
.HasMany<Student>(g => g.Students)
.WithRequired(s => s.CurrentGrade)
.HasForeignKey<int>(s => s.CurrentGradeId);
Ví dụ trên sẽ tạo các bảng sau trong cơ sở dữ liệu.
Cấu hình khóa ngoại NotNull bằng Fluent API
Trong quy ước 1, chúng ta đã thấy rằng nó tạo ra một mối quan hệ một-nhiều tùy chọn, từ đó tạo ra một cột khóa ngoại có thể Null trong cơ sở dữ liệu.
Để biến nó thành cột NotNull, hãy sử dụng phương thức HasRequired()
như bên dưới.
modelBuilder.Entity<Student>()
.HasRequired<Grade>(s => s.CurrentGrade)
.WithMany(g => g.Students);
Cấu hình Cascade Delete bằng Fluent API
Cascade Delete có nghĩa là tự động xóa các các bản ghi con liên quan khi bản ghi cha bị xóa. Ví dụ, nếu lớp bị xóa thì tất cả các sinh viên trong lớp đó cũng sẽ bị xóa tự động. Ví dụ sau cấu hình Cascade Delete bằng phương thức WillCascadeOnDelete
.
modelBuilder.Entity<Grade>()
.HasMany<Student>(g => g.Students)
.WithRequired(s => s.CurrentGrade)
.WillCascadeOnDelete();