原文連接:https://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspxjavascript
EF 6 Code-First系列文章目錄:html
這裏咱們將學習如何在兩個實體(領域類)之間配置一對多的關係。
咱們使用Student和Grade兩個實體配置一對多的關係,一個Grade中能夠有不少的Students。java
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; }
}
在上面兩個實體實現一對多關係以後,數據庫中就會生成下面兩個表:
typescript
一對多的關係,能夠經過下面的方式進行配置:數據庫
在EF中有某些約定,只要實體遵循這些約定,EF就會爲咱們在數據庫自動生成一對多的關係數據表。你不用進行任何其餘的配置。
咱們來看看一對多關係的全部的約定狀況吧:api
咱們想要在Student實體和Grade實體之間創建一對多的關係,而且不少學生關聯到一個Grade。這就意味着,每個Student實體指向一個Grade。這種狀況能夠經過在Student類中包含一個Grade類型的導航屬性作到,例如:app
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; }
}
在上面的例子中,Student類包含了一個Grade類型的導航屬性,這樣就會在Students和Grades表之間生成一對多關係,而且生成外鍵Grade_GradeId:
ide
請注意:由於應用類型的屬性是可空的,因此在Students表中建立的外鍵列Grade_GradeId是可空的。你可使用Fluent API配置不爲空的外鍵列。學習
另一個約定就是,在主體實體中包含一個集合類型的導航屬性,例如:測試
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; }
}
在上面例子中Grade實體中包含一個集合類型ICollection的導航屬性Students.因此這種也會在Students和Grades表之間生成一對多的關係。生成的數據庫結構和約定1中同樣。
在兩個實體中,都包含導航屬性:
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; }
}
在上面的代碼中,Student實體包含一個Grade類型的導航屬性,一樣,Grade實體包含一個集合類型ICollection的屬性.結果也是在兩個表之間生成一對多的關係。生成的數據庫結果和約定1,約定2中同樣。
在兩個實體中,完整的定義關係,也會根據約定生成一對多的關係表:
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; }
}
在上面的例子中,Student實體中,包含一個外鍵屬性GradeId,還有一個Grade類型的導航屬性。這樣就會生成一對多的關係表。而且Student表中生成的外鍵GradeId是不可空的:
若是GradeId是可空的int類型,那麼就會生成可空的外鍵:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int? GradeId { get; set; }
public Grade Grade { get; set; }
}
上面的代碼將會生成一個可空的外鍵GradeId,?只是類型Nullable的簡寫。
一般狀況下,在EF中你不用配置一對多的關係,由於默認的約定,已經幫咱們配置好了。然而你可使用Fluent API來配置一對多的關係,比默認生成的表更好維護一點。
看看下面的Student和Grade實體:
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; }
}
你可使用Fluent API,重寫上下文類中的OnModelCreating方法,來給上面的代碼配置一對多的關係:
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);
}
}
咱們來一步步理解上面的代碼:
還有另一種方式配置一對多關係,就是從Grade實體開始配置,而不是Student實體。下面的代碼,生成的數據庫和上面的代碼生成的是同樣的:
modelBuilder.Entity<Grade>()
.HasMany<Student>(g => g.Students)
.WithRequired(s => s.CurrentGrade)
.HasForeignKey<int>(s => s.CurrentGradeId);
代碼生成的數據庫結構以下:
在約定1中,咱們看到生成的一對多關係中,外鍵是可空的,爲了生成不爲空的外鍵列,咱們能夠這樣,使用HasRequired方法:
modelBuilder.Entity<Student>()
.HasRequired<Grade>(s => s.CurrentGrade)
.WithMany(g => g.Students);
級聯刪除意味着:當父行被刪除以後,自動刪除相關的子行。例如:若是Grade被刪除了,那麼全部在這個Grade中的Students應該一樣被自動刪除。下面的代碼,使用WillCascadeOnDelete方法配置級聯刪除:
modelBuilder.Entity<Grade>()
.HasMany<Student>(g => g.Students)
.WithRequired(s => s.CurrentGrade)
.WillCascadeOnDelete();
好了,一對多的關係就介紹到這裏,下面一節講解多對多關係。