我从数据库中查询学校实体。然后,我试着通过这样做来获得该学校的学生人数:
var school = context.schools.Where(s=>s.ID == 1).Single();
int cnt = school.students.Count();
但我发现发送到数据库的查询获取该学校的所有学生记录,并且计数在应用服务器上完成。
以下内容只是从数据库中查询COUNT(),因为它应该是:
int cnt = context.students.Where(s=>s.schoolID == 1).Count();
为什么这两种方法之间存在这样的差异?第一个查询不应该使用COUNT()来提高效率吗?
注意:不查询学校实体不是一种选择,因为我正在使用它的一些字段。
答案 0 :(得分:2)
school.students.Count()
通过 LazyLoading 工作,所以首先,您在客户端获取学生:school.students
然后.Count()
,正如您已经写过的那样。但是您可以按照方式修改代码,这将执行一次数据库访问:
var answer = (from sch in context.schools
where sch.ID == 1
join st in context.students on sch.ID equals st.schoolID into subs
from sub in subs.DefaultIfEmpty()
group sub by new { sch.ID, sch.Name, sch.Location } into gr
select new
{
gr.Key.Name,
gr.Key.Location,
Count = gr.Count(x => x != null)
}).First();
sch.Name
,sch.Location
- 学校的字段,您需要进一步使用
答案 1 :(得分:2)
查询在最后一刻运行,以使它们尽可能高效 - 称为延迟加载 - 在您的第一个示例中,您的Single()
调用强制数据提供程序不像您希望的那样懒惰。
当您致电Single()
时,您要求提供整个Student
记录 - 所有学生记录列表中的第一个记录,因此查询必须运行(GET SchoolId, SchoolName, .... FROM SCHOOLS WHERE SchoolId = 1
)为你提供数据。然后,您致电Count()
,重播查询,只选择COUNT
。
在第二个示例中,您只能在Count()
来电后致电Where()
。由于您尚未访问任何数据,Where()
并未强制执行查询,因此数据提供程序在评估后可以巧妙地仅对数据库进行GET COUNT
类型查询Count()
。
如何判断LINQ方法是否会播放&#39;您的查询?我记得的方式是,如果它返回IQueryable<T>
,它将不播放你的查询,其他任何东西,它都会。
答案 2 :(得分:0)
关于延迟加载的全部内容,但效果是双重的:
context.schools.Where(s=>s.ID == 1).Single()
将返回一个没有任何学生加载的学校实体(延迟加载第1部分)。但是,school.students.Count()
部分,.students
必须为所有学生打到数据库 - 因为他们没有加载到第一行,所以他们都将被加载(因为你暗中要求那个 - 延迟加载第2部分)然后 Count()
开火。要减少通话,请按照您的建议执行:int cnt = context.students.Where(s=>s.schoolID == 1).Count();
,这将导致2个db调用,或创建分组结果,如the original answer