此代码似乎返回所有行

时间:2014-06-12 08:14:40

标签: asp.net linq entity-framework

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查询之外。

2 个答案:

答案 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,您将获得内存中的所有内容,并在此之后应用查询。