实体框架计数效率

时间:2017-12-22 03:36:51

标签: c# entity-framework

我从数据库中查询学校实体。然后,我试着通过这样做来获得该学校的学生人数:

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()来提高效率吗?

注意:不查询学校实体不是一种选择,因为我正在使用它的一些字段。

3 个答案:

答案 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.Namesch.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)

关于延迟加载的全部内容,但效果是双重的:

  1. context.schools.Where(s=>s.ID == 1).Single()将返回一个没有任何学生加载的学校实体(延迟加载第1部分)。但是,
  2. 由于school.students.Count()部分,
  3. .students必须为所有学生打到数据库 - 因为他们没有加载到第一行,所以他们都将被加载(因为你暗中要求那个 - 延迟加载第2部分)然后 Count()开火。
  4. 要减少通话,请按照您的建议执行:int cnt = context.students.Where(s=>s.schoolID == 1).Count();,这将导致2个db调用,或创建分组结果,如the original answer