此代码似乎返回所有行

Dal*_*ser 0 linq asp.net entity-framework

match match = myRepo.GetAll()
    .Where(m => m.personId == personId)
    .Where(m => m.companyId == companyId).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

现在有超过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>();
}
Run Code Online (Sandbox Code Playgroud)

我只是想要理智地检查我的理论是否正确,有些人认为因为它的IEnumerable它不应该这样做,但它的返回首先必须在本地函数中循环,因为它在linq查询之外的地方.

Jon*_*eet 5

您的GetAll方法返回IEnumerable<T>(而不是IQueryable<T>)的事实意味着您的Where调用使用LINQ to Objects,而不是EF.换句话说,该查询是在本地获取所有数据,并在您的过程中对其进行过滤.这不好.

考虑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;
}
Run Code Online (Sandbox Code Playgroud)

然后你仍然在"可查询的土地".请注意,这仍然存在缺陷,因为您希望任何其他查询之后应用分页,而不是之前.所以你可能真的想要一个方法返回_db.Set<T>(),然后有一个单独的扩展方法进行分页.(我很担心您的分页实现需要您计算完整的结果,请注意......)