本篇文章中,您将学习如何使用Entity Framework Core中的Fluent API配置两个实体之间的多对多关系。
让我们实现以下Student
和Course
实体之间的多对多关系,其中一个学生可以注册许多课程,同样,一门课程可以由许多学生加入。
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中,尚未实现。我们必须为连接表创建一个连接实体类。上述Student
和Course
实体的加入实体应包括每个实体的外键属性和引用导航属性。
配置多对多关系的步骤如下:
- 定义一个新的连接实体类,其中包括每个实体的外键属性和引用导航属性。
- 定义其他两个实体和实体加盟之间的一个一对多的关系,通过在实体的集合导航属性两侧(
Student
和Course
,在这种情况下)。 - 使用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);