EF 仅加载筛选的子条目



>假设我有典型的学生和课程类,作为实体拉取并通过EF6自动生成。 例

class Student {
string name,
virtual ICollection<Course> Courses
virtual ICollection<A> example a
virtual ICollection<B> example b
virtual ICollection<C> example c
etc...
}
class Course {
DateTime courseDate,
virtual Student Student
etc...
}

我希望能够获得明天有课程的学生名单,并且只在孩子名单中拥有该课程。(假设每天最多1道菜(

我尝试过的事情...

List<Student> Method 1 (DateTime date)
{
ctx.Configurations.LazyLoadingEnabled = false;
return (from s in ctx.Students.Include(x=>x.Course)
join c in ctx.Courses
where c.courseDate == date
select s).ToList();
}

结果:有课程的学生列表(但课程对象中没有任何内容(

List<Student> Method 2 (DateTime date)
{
return ctx.Students.Where(x=>x.Courses.Any(y=>y.courseDate==date)).ToList()
}

结果:附加了所有属性且未筛选的学生列表。

List<Student> Method 3 (DateTime date)
{
ctx.Configurations.LazyLoadingEnabled = false;
return ctx.Students.Include(x=>x.Courses).Where(x=>x.Courses.Any(y=>y.courseDate==date)).ToList()
}

结果:仅附加了课程属性但仍未筛选的学生列表。

List<Student> Method 4 (DateTime date)
{
ctx.Configurations.LazyLoadingEnabled = false;
return 
ctx.Students.Include(x=>x.Courses).Where(x=>x.Courses.Select(y=>y.courseDate).Contains(date)).ToList()
}

结果:同上

名单还在继续。

我不希望在初始查询后提取和过滤数据。

谁能帮忙。

所以你有学生和课程。 每个学生参加零个或多个课程。我认为课程由零名或多名学生(多对多(参加。在我看来,您设计了每门课程都只有一个学生(一对多(参加。

如果您真的打算一对多,您的课程类应该略有变化:

class Course
{
public int Id {get; set;}
public DateTime CourseDate {get; set;}
...
public int StudentId {get; set;}   // <======= !!!
public virtual Student Student {get; set;}
}

回到你的问题

你写道:

我希望能够获得明天有课程的学生名单,并且只在孩子名单中拥有该课程。

从您的示例中,您似乎希望所有学生明天至少拥有一门课程,以及该学生明天拥有的所有课程。

通常,在使用实体框架时,像您一样使用virtual ICollections就足够了:

DateTime tomorrow = ...
var studentsWithCoursesOnDate = dbContext.Students.Select(student => new
{
// Select only the properties that you plan to use:
Id = student.Id,
Name = student.Name,
... 
CoursesOnDate = student.Courses
.Where(course => course.CourseDate == tomorrow)
.Select(course => new
{
// again: only the properties that you plan to use
Id = course.Id,
Title = course.Title,
...
// not needed, you know the value
// StudentId = course.StudentId,
})
.ToList(),
})
.ToList();

这应该适用于完整的实体框架。实体框架知道表之间的关系,并将为您执行正确的 GroupJoin。 我听说您不能在 EF 核心中使用虚拟 ICollections,我还没有验证过。

如果你想做小组加入你的:

DateTime tomorrow = ...
IQueryable<Course> tomorrowCourses = dbContext.Courses
.Where(course => course.CourseDate == tomorrow);
var studentsWithCoursesOnDate = dbContext.Students
.GroupJoin(tomorrowCourses,             // GroupJoin Students and tomorrow's Courses
student => student.Id,                  // from every Student take the Id
course => course.StudentId,             // from every Course take the foreign key
(student, coursesOfThisStudent) => new  // when they match, make one new object
{
// again: select only the properties that you plan to use:
Id = student.Id,
Name = student.Name,
...
CoursesOnDate = coursesOfThisStudent.Select(course => new
{
// again: only the properties that you plan to use
Id = course.Id,
Title = course.Title,
...
})
.ToList(),
})
.ToList();

注意:标识符coursesOfThisStudent实际上只包含该学生明天的课程,但这会使标识符变得不必要地长。

我使用 Select,因为 Include 获取匹配数据行的所有列,包括外键和您现在可能不打算使用的其他数据。包含很少有效。

查询数据时,请始终使用Select选择所需的值。仅当您计划更改(更新(提取的数据时才使用"包括"。

最新更新