我从数据库中查询学校实体。然后,我尝试通过这样做来获取该学校的学生数量:
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()来提高效率吗?
注意:不查询学校实体是不可行的,因为我正在使用它的一些字段。
发布于 2017-12-22 13:46:12
学生通过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 -学校的字段,需要进一步使用
发布于 2017-12-22 15:59:09
查询在可能的最后时刻运行,以使它们尽可能高效-称为延迟加载-在您的第一个示例中,您的Single()调用迫使数据提供程序比您希望的要少一些延迟。
当您调用Single()时,您请求的是整个Student记录-所有学生记录列表中的第一条记录,因此查询必须运行(GET SchoolId, SchoolName, .... FROM SCHOOLS WHERE SchoolId = 1)才能获得该数据。然后调用Count(),除了只选择COUNT之外,重播查询。
相反,在第二个示例中,您只能在Where()调用之后调用Count()。Where()不会强制执行查询,因为您还没有访问任何数据,因此数据提供程序只能在评估Count()之后对数据库执行GET COUNT类型的查询。
如何判断LINQ方法是否会“播放”你的查询?我记得的方式是,如果它返回IQueryable<T>,它将不会播放您的查询,其他任何内容,它都会。
发布于 2017-12-22 16:14:52
这一切都是关于延迟加载的,但其效果是双重的:
context.schools.Where(s=>s.ID == 1).Single()将返回一个没有加载任何学生的学校实体(惰性加载第1部分)。但是,由于.students部分的原因,school.students.Count()必须访问所有学生的数据库-因为他们不是在第一行加载的,所以他们都将被加载(因为您隐式地请求了这一点-延迟加载部分2),然后Count()触发。要减少调用次数,可以按照您的建议执行:int cnt = context.students.Where(s=>s.schoolID == 1).Count();,这将导致2个db调用,或者像在the original answer中那样创建分组结果
https://stackoverflow.com/questions/47935544
复制相似问题