12.翻译系列:EF 6 中配置一对多的关系【EF 6 Code-First系列】

原文连接: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; }
}

在上面两个实体实现一对多关系以后,数据库中就会生成下面两个表:
enter description heretypescript

一对多的关系,能够经过下面的方式进行配置:数据库

  1. 经过默认的约定
  2. 使用Fluent API进行配置
经过默认约定配置一对多的关系

在EF中有某些约定,只要实体遵循这些约定,EF就会为咱们在数据库自动生成一对多的关系数据表。你不用进行任何其余的配置。
咱们来看看一对多关系的全部的约定状况吧:api

约定1:

咱们想要在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:
enter description hereide

请注意:由于应用类型的属性是可空的,因此在Students表中建立的外键列Grade_GradeId是可空的。你可使用Fluent API配置不为空的外键列。学习

约定2:

另一个约定就是,在主体实体中包含一个集合类型的导航属性,例如:测试

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中同样。

约定3:

在两个实体中,都包含导航属性:

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中同样。

约定4:

在两个实体中,完整的定义关系,也会根据约定生成一对多的关系表:

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是不可空的:

 

enter description here
enter description here

 

若是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的简写。

使用Fluent API配置一对多的关系

一般状况下,在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);         
    }
}

咱们来一步步理解上面的代码:

  • 首先从一个实体类开始配置,因此modelBuilder.Entity()就是从Student实体开始配置。
  • 而后,.HasRequired(s => s.CurrentGrade)指定Student实体,必需要有CurrentGrade属性,这就会在数据库中生成一个不为空的外键。
  • 如今,如今就是配置关系的另一边,也就是Grade实体。
  • .WithMany(g => g.Students)指定Grade实体包含不少Student实体,这里能够经过ICollcetion类型的属性推断出来。
  • 而后,若是Student实体,不遵循外键的约定【ID property convention】,咱们就能够经过HasForeignKey方法指定外键的名称。
  • HasForeignKey(s => s.CurrentGradeId),指定了Student实体中的外键属性。

还有另一种方式配置一对多关系,就是从Grade实体开始配置,而不是Student实体。下面的代码,生成的数据库和上面的代码生成的是同样的:

modelBuilder.Entity<Grade>()
    .HasMany<Student>(g => g.Students)
    .WithRequired(s => s.CurrentGrade)
    .HasForeignKey<int>(s => s.CurrentGradeId);

代码生成的数据库结构以下:
enter description here

使用Fluent API配置不为空的外键列

在约定1中,咱们看到生成的一对多关系中,外键是可空的,为了生成不为空的外键列,咱们能够这样,使用HasRequired方法:

modelBuilder.Entity<Student>()
    .HasRequired<Grade>(s => s.CurrentGrade)
    .WithMany(g => g.Students);
使用Fluent API配置级联删除

级联删除意味着:当父行被删除以后,自动删除相关的子行。例如:若是Grade被删除了,那么全部在这个Grade中的Students应该一样被自动删除。下面的代码,使用WillCascadeOnDelete方法配置级联删除:

modelBuilder.Entity<Grade>()
    .HasMany<Student>(g => g.Students)
    .WithRequired(s => s.CurrentGrade)
    .WillCascadeOnDelete();

好了,一对多的关系就介绍到这里,下面一节讲解多对多关系。

相关文章
相关标签/搜索