我开始学习MVC,并尝试使用实体框架代码优先的方法创建数据库。我有一个学生表和一个科目表,每个学生都可以有多个科目,一个科目可以有很多学生。链接器表有一个分数列,因为每个学生对每个科目都有不同的分数。我在尝试创建dtabase时遇到一个错误,告诉我在模型生成过程中检测到一个或多个验证错误。这是我的模型。
public class Course
{
[Key]
public int CourseId { get; set; }
public string CourseName { get; set; }
public List<Student> Students { get; set; }
}
public class Student
{
[Key]
public int StudentId { get; set; }
public string Name { get; set; }
public List<Course> Courses { get; set; }
}
public class StudentCourses
{
[Key]
public Course Course { get; set; }
[Key]
public Student Student { get; set; }
public double Grade { get; set; }
}
public class CourseDb: DbContext
{
public DbSet<Course> Courses { get; set; }
public DbSet<Student> Students { get; set; }
public DbSet<StudentCourses> StudentCourses { get; set; }
}
我在谷歌上搜索了一下,看到了一些多对多关系的方法,但没有一种方法在链接器表中有额外的属性(Grade属性)。
不幸的是,如果您使用具有附加属性的中间表(或者实际上,如果您定义了一个特定的类来管理该关系,而不是让EF自动处理它),您将失去直接导航属性的能力。
您必须将您的型号更改为:
public class Course
{
...
public List<StudentCourses> Students { get; set; }
}
和
public class Student
{
...
public List<StudentCourses> Courses { get; set; }
}
然后,例如,如果你正在迭代某个特定学生的课程列表:
@foreach (var course in student.Courses)
{
@course.Course.CourseName, @course.Grade
}
此外,值得一提的是,这可能会导致1+N的查询,所以如果你要这样做,你应该在查询学生时急切地加载课程:
var student = db.Students.Include('Courses.Course').SingleOrDefault(m => m.StudentId == id);
编辑
实际上你在这里遇到了很多问题。我抓住了第一个,就停在那里,没有注意到还有什么问题。您仍然会遇到错误,因为您在中介表上使用了复合键(学生和课程外键的组合)。这很好,但当您指定多个键时,您还必须指定列顺序:
[Key, Column(Order = 0)]
public Course Course { get; set; }
[Key, Column(Order = 1)]
public Student Student { get; set; }
我也不确定是否可以将Key
与导航属性一起使用。我从来没有试过自己做,但它可能会起作用。如果你仍然有错误,我会尝试显式外键属性:
[Key, Column(Order = 0)]
public int CourseId { get; set; }
public Course Course { get; set; }
[Key, Column(Order = 1)]
public int StudentId { get; set; }
public Student Student { get; set; }