本节,我们将学习如何在Code First中配置两个实体之间的一对多关系。
举一个Student和Standard(年级)实体的例子,其中,一个Standard可以包括许多Student。 所以Student与Standard实体之间的关系将是一对多的。
使用DataAnnotation配置一对多关系
来看下面Student与Standard实体:
public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } public virtual Standard Standard { get; set; } } public class Standard { public Standard() { Students = new List<Student>(); } public int StandardId { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } }
上述示例中,Student实体包括导航属性Standard,Standard实体包括Student的集合属性。 这是形成一对多关系的默认约定。
如果实体类遵循此约定,则我们不需要使用DataAnnotations或Fluent API配置一对多关系。
EF Code First将通过在Student表中添加Standard_StandardId列来创建一对多关系,如下所示:
实体包括外键Id属性:
建议在实体类中包含外键属性。 例如,Student实体包含自动变为foreignkey属性的StandardId属性,因为它符合外键<Type Name> Id的约定。
如果foreignkey属性名称不符合约定,例如,Student实体对于Standard实体使用了不同名称的外键(不是StandardId),那么我们需要在属性上应用ForeignKey属性。
例如,以下Student实体包括StandardRefId属性:
public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } public int StdandardRefId { get; set; } [ForeignKey("StandardRefId")] public virtual Standard Standard { get; set; } } public class Standard { public Standard() { Students = new List<Student>(); } public int StandardId { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } }
上述示例中,ForeignKey属性应用于Standard导航属性以指定Standard属性的foreignkey属性名称。所以EF将创建一个StandardRefId列作为FK,如下所示:
使用Fluent API配置一对多关系
这里,我们将学习使用Fluent API的Student和Standard实体之间的一对多关系。
让我们为以下Student和Standard实体配置一对多关系:
public class Student { public Student(){ } public int StudentId { get; set; } public string StudentName { get; set; } public int StandardId { get; set; } public virtual Standard Standard { get; set; } } public class Standard { public Standard() { StudentsList = new List<Student>(); } public int StandardId { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } }
你可以按照一下代码进行配置:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //one-to-many modelBuilder.Entity<Student>() .HasRequired<Standard>(s => s.Standard) // Student entity requires Standard .WithMany(s => s.Students); // Standard entity includes many Students entities }
假设Student和Standard实体类没有遵循外键的Code First约定:
public class Student { public Student(){ } public int StudentId { get; set; } public string StudentName { get; set; } //StdId is not following code first conventions name public int StdId { get; set; } public virtual Standard Standard { get; set; } } public class Standard { public Standard() { StudentsList = new List<Student>(); } public int StandardId { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } }
所以,你可以通过Fluent API使用Student实体类配置一对多关系,如下所示:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //one-to-many modelBuilder.Entity<Student>() .HasRequired<Standard>(s => s.Standard) .WithMany(s => s.Students) .HasForeignKey(s => s.StdId); }
可以看到,modelBuilder.Entity <Student>().HasRequired <Standard>(s => s.Standard)指定Student实体需要NotNull标准导航属性。
.WithMany(s => s.Students).HasForeignKey(s => s.StdId)指定Standard实体可以包括多个Student在学生集合属性中,外键是StdId。
另一种可行的方式:我们也可以从Standard实体开始:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //configure one-to-many modelBuilder.Entity<Standard>() .HasMany<Student>(s => s.Students) //Standard has many Students .WithRequired(s => s.Standard) //Student require one Standard .HasForeignKey(s => s.StdId);//Student includes specified foreignkey property name for Standard }
上面的代码将创建以下数据库:
注意StdId不为空列。 所以每次添加或更新Student时,都必须为Student实体指定Standard。
一对多关系中的可空外键:
使用HasOptional方法代替HasRequired方法使外键列为空。
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //one-to-many modelBuilder.Entity<Student>() .HasOptional<Standard>(s => s.Standard) .WithMany(s => s.Students) .HasForeignKey(s => s.StdId); }
下节学习多对多关系的配置。