Entity Framework Core系列教程-15-Fluent API配置多对多关系
在Entity Framework Core中配置多对多关系
在这里,您将学习如何使用Entity Framework Core中的Fluent API配置两个实体之间的多对多关系。
让我们在以下学生和课程实体之间实现多对多关系,其中一个学生可以报名参加许多课程,并且以同样的方式,许多学生可以加入一门课程。
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string CourseName { get; set; }
public string Description { get; set; }
}
数据库中的多对多关系由联接表表示,联接表包括两个表的外键。同样,这些外键是复合主键。
约定
Entity Framework Core中没有可用于自动配置多对多关系的默认约定。您必须使用Fluent API对其进行配置。
Fluent API
在Entity Framework 6.x或更低版本中,EF API用于为多对多关系创建联接表。我们不需要为联接表创建联接实体(但是,我们当然可以在EF 6中显式创建联接实体)。
在Entity Framework Core中,这尚未实现。我们必须为联接表创建联接实体类。上述学生和课程实体的加入实体应包括每个实体的外键属性和参考导航属性。
配置多对多关系的步骤如下:
- 定义一个新的加入实体类,该类包括每个实体的外键属性和引用导航属性。
- 通过在两侧的实体中包括集合导航属性(在本例中为“学生”和“课程”),定义其他两个实体与加入实体之间的一对多关系。
- 使用Fluent API将加入实体中的两个外键都配置为组合键。
因此,首先,定义连接实体StudentCourse,如下所示:
public class StudentCourse
{
public int StudentId { get; set; }
public Student Student { get; set; }
public int CourseId { get; set; }
public Course Course { get; set; }
}
上述加入实体StudentCourse分别包括引用导航属性Student和Course以及它们的外键属性StudentId和CourseId(外键属性遵循约定)。
现在,我们还需要在Student-> StudentCourse和Course-> StudentCourse实体之间配置两个单独的一对多关系。我们可以通过遵循一对多关系的约定来做到这一点,如下所示。
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public IList<StudentCourse> StudentCourses { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string CourseName { get; set; }
public string Description { get; set; }
public IList<StudentCourse> StudentCourses { get; set; }
}
如您在上面所看到的,Student和Course实体现在包括StudentCourse类型的集合导航属性。 StudentCourse实体已经包含了Student和Course的外键属性和导航属性。这使其在Student&StudentCourse与Course&StudentCourse之间建立了完全定义的一对多关系。
现在,外键必须是联接表中的复合主键。只能使用Fluent API进行配置,如下所示。
public class SchoolContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=.\\SQLEXPRESS;Database=EFCore-SchoolDB;Trusted_Connection=True");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<StudentCourse>().HasKey(sc => new { sc.StudentId, sc.CourseId });
}
public DbSet<Student> Students { get; set; }
public DbSet<Course> Courses { get; set; }
public DbSet<StudentCourse> StudentCourses { get; set; }
}
在上面的代码中,modelBuilder.Entity<StudentCourse>().HasKey(sc => new { sc.StudentId, sc.CourseId }) 将StudentId和CourseId配置为组合键。
如果实体遵循与加入实体的一对多关系的约定,则可以通过这种方法配置多对多关系。假设外键属性名称不遵循约定(例如,SID代替StudentId,CID代替CourseId),则可以使用Fluent API对其进行配置,如下所示。
modelBuilder.Entity<StudentCourse>().HasKey(sc => new { sc.SId, sc.CId });
modelBuilder.Entity<StudentCourse>()
.HasOne<Student>(sc => sc.Student)
.WithMany(s => s.StudentCourses)
.HasForeignKey(sc => sc.SId);
modelBuilder.Entity<StudentCourse>()
.HasOne<Course>(sc => sc.Course)
.WithMany(s => s.StudentCourses)
.HasForeignKey(sc => sc.CId);
注意:EF团队将包含一项功能,将来我们无需为多对多关系创建加入实体。在GitHub上跟踪此问题。