match match = myRepo.GetAll()
.Where(m => m.personId == personId)
.Where(m => m.companyId == companyId).FirstOrDefault();
现在有超过100万条记录,需要很长时间。我重构它来做一个linq查询,它立即运行。这表明myRepo.GetAll()返回所有内容,然后循环遍历每一行以执行where而不是在db级别执行此操作。
GetAll看起来像这样:
public virtual IEnumerable<T> GetAll(Paging p = null)
{
// Get the set as a queryable.
IQueryable<T> q = _db.Set<T>();
if(p != null)
{
p.TotalCount = q.Count();
q = q.Skip(p.StartAt).Take(p.PageSize);
}
// Return the enumerable.
return q.AsEnumerable<T>();
}
我只是想要理智地检查我的理论是否正确,有些人认为因为它的IEnumerable它不应该这样做,但它的返回首先必须在本地函数中循环,因为在哪里&#39 ; s在linq查询之外。
答案 0 :(得分:5)
您的GetAll
方法返回IEnumerable<T>
(而不是IQueryable<T>
)这一事实意味着您的Where
调用正在使用LINQ to Objects,而不是EF。换句话说,该查询在本地提取 all 数据,并在您的过程中对其进行过滤。那不好。
考虑将GetAll
更改为:
public virtual IQueryable<T> GetAll(Paging p = null)
{
// Get the set as a queryable.
IQueryable<T> q = _db.Set<T>();
if(p != null)
{
p.TotalCount = q.Count();
q = q.Skip(p.StartAt).Take(p.PageSize);
}
return q;
}
然后你仍然在“可查询的土地”。请注意,这仍然是仍然有缺陷,因为您希望在之后应用分页,而不是之前。所以你可能真的想让一个方法返回_db.Set<T>()
,然后有一个单独的扩展方法进行分页。 (我很担心您的分页实现需要您计算完整的结果,请注意......)
答案 1 :(得分:3)
使用AsEnumberable
,您将获得内存中的所有内容,并在此之后应用查询。