0

我有以下模型(为这个问题简化了):

public class Student
{
    public int ID { get; set; }
    public virtual ICollection<StudentCourse> StudentCourses { get; set; }

     public Student(){
        StudentCourses = new List<StudentCourse>();
    }
}

public class StudentCourse
{
    public int ID { get; set; }
    public string Grade { get; set; }
    public int StudentID { get; set; }
    public int CourseID { get; set; }

    public virtual Student Student { get; set; }
    public virtual Course Course { get; set; }
}

public class Course
{
    public int ID { get; set; }        
    public virtual ICollection<StudentCourse> StudentCourses { get; set; }

    public Course() {
        StudentCourses = new List<StudentCourse>();
    }
}

一切都在我的 DbContext 类中链接并按预期工作。我想找到所有参加过课程的学生,所以我这样做:

var query = db.Students
            .Where(s => s.StudentCourses.Course.ID == 11); 

但它失败了,因为由于某种原因,EF 看不到 StudentCourse 和 Course 之间的链接。错误信息是:

'System.Collections.Generic.ICollection' 不包含'Course' 的定义,并且找不到接受'System.Collections.Generic.ICollection' 类型的第一个参数的扩展方法'Course'(您是否缺少 using 指令还是程序集参考?)。

但是,以下工作正常:

var query = db.StudentCourses
            .Where(s => s.Course.ID == 11)
            .Select(s=>s.Students);

这是一个错误还是我做错了什么?

4

2 回答 2

1

StudentCourses 是一个课程列表,您不能使用 .Course 访问其中的单个课程。为此,您需要使用适用于单个记录的子句,例如 select、where、any 等(大多数采用 lambda 表达式的 IEnumerable 扩展都是为此目的。)

var query = db.Students.Where(s => s.StudentCourses.Any(r => r.Course.CourseID == 11)); 

如果您想使用 db.Students,很好,但是您发布的第二个示例在语义上可能更接近您正在做的事情。StudentCourses 代表学生和课程之间的联系。您的 where 子句仅限于特定课程,select 子句将学生课程集合投射到其连接的学生上。

于 2012-05-11T16:32:01.090 回答
1

为什么这部分在您的代码中:

public Student(){
    StudentCourses = new List<StudentCourse>();
}

我做的时候不需要包括那部分,只要有它就可以了

public virtual ICollection<StudentCourse> StudentCourses { get; set; }

全部靠自己。您通过提前分配列表来阻止内部准备工作。


请注意

var query = db.Students
              .Where(s => s.StudentCourses.Course.ID == 11);

不一定会起作用,因为 StunderdCourses 可能会被懒惰地评估,你会想要使用:

var query = db.Students
              .Include("StudentCourses")
              .Where(s => s.StudentCourses.Course.ID == 11);

这将确保每个学生的 StudentCourses 也包含在查询中。


请注意,上面的查询效率很低,因为您正在获取所有学生,并且对于每个学生,您正在获取他的所有课程,您最后建议的代码要好得多,因为它首先查找正确的课程,然后找到属于的学生对它:

var query = db.StudentCourses
              .Include("Course")
              .Where(s => s.Course.ID == 11)
              .Select(s=>s.Students);

请注意Include再次使用,这在执行惰性评估的服务器上是必需的。


但是,请注意,该类实际上具有 CourseID 属性,因此您也可以这样做:

var query = db.StudentCourses
              .Where(s => s.CourseID == 11)
              .Select(s=>s.Students);
于 2012-05-12T11:00:58.497 回答