c# - 方法 ‘Skip’ 仅支持 LINQ to Entities 中的排序输入。必须在方法 ‘OrderBy’ 之前调用方法 ‘Skip’

标签 c# linq entity-framework

Visual Studio 2013 Update 1 中使用 Entity Framework 6.0.2.NET 4.5.1 DbContext连接到 SQL Server:

我有一个很长的过滤器链,我正在根据调用者的期望结果将其应用于查询。一切都很好,直到我需要添加分页。这是一瞥:

IQueryable<ProviderWithDistance> results = (from pl in db.ProviderLocations
                                            let distance = pl.Location.Geocode.Distance(_geo)
                                            where pl.Location.Geocode.IsEmpty == false
                                            where distance <= radius * 1609.344
                                            orderby distance
                                            select new ProviderWithDistance() { Provider = pl.Provider, Distance = Math.Round((double)(distance / 1609.344), 1) }).Distinct();

if (gender != null)
{
    results = results.Where(p => p.Provider.Gender == (gender.ToUpper() == "M" ? Gender.Male : Gender.Female));
}

if (type != null)
{
    int providerType;
    if (int.TryParse(type, out providerType))
        results = results.Where(p => p.Provider.ProviderType.Id == providerType);
}

if (newpatients != null && newpatients == true)
{
    results = results.Where(p => p.Provider.ProviderLocations.Any(pl => pl.AcceptingNewPatients == null || pl.AcceptingNewPatients == AcceptingNewPatients.Yes));
}

if (string.IsNullOrEmpty(specialties) == false)
{
    List<int> _ids = specialties.Split(',').Select(int.Parse).ToList();

    results = results.Where(p => p.Provider.Specialties.Any(x => _ids.Contains(x.Id)));
}

if (string.IsNullOrEmpty(degrees) == false)
{
    List<int> _ids = specialties.Split(',').Select(int.Parse).ToList();

    results = results.Where(p => p.Provider.Degrees.Any(x => _ids.Contains(x.Id)));
}

if (string.IsNullOrEmpty(languages) == false)
{
    List<int> _ids = specialties.Split(',').Select(int.Parse).ToList();

    results = results.Where(p => p.Provider.Languages.Any(x => _ids.Contains(x.Id)));
}

if (string.IsNullOrEmpty(keyword) == false)
{
    results = results.Where(p =>
        (p.Provider.FirstName + " " + p.Provider.LastName).Contains(keyword));
}

这是我添加到底部的分页(skipmax 只是 int 参数):

if (skip > 0)
    results = results.Skip(skip);

results = results.Take(max);

return new ProviderWithDistanceDto { Locations = results.AsEnumerable() };

现在回答我的问题:

  1. 如您所见,我在初始 LINQ 查询中执行了一个 orderby,那么为什么它会提示我需要执行一个 OrderBy在做 Skip 之前(我以为我是?)...

  2. 我假设它不会变成 SQL 查询并在我枚举结果之前执行,这就是为什么我等到最后一行才返回结果 AsEnumerable()。这是正确的做法吗?

  3. 如果我必须在执行 Skip 之前枚举结果和 Take这将如何影响性能?显然我想让 SQL Server 完成繁重的工作并只返回请求的结果。或者这无关紧要(或者我听错了)?

最佳答案

I am doing an orderby in the initial LINQ query, so why is it complaining that I need to do an OrderBy before doing a Skip (I thought I was?)

你的 result作为有序可查询项正确开始:第一行查询返回的类型是 IOrderedQueryable<ProviderWithDistance> ,因为你有一个 order by条款。但是,添加 Where在它之上使您的查询成为普通的 IQueryable<ProviderWithDistance>再次导致您在路上看到的问题。从逻辑上讲,这是一回事,但内存中查询定义的结构暗示着不同。

要解决此问题,请删除 order by在原始查询中,并在准备好进行分页之前添加它,如下所示:

    ...
    if (string.IsNullOrEmpty(languages) == false)
        ...
    if (string.IsNullOrEmpty(keyword) == false)
        ...
    result = result.OrderBy(r => r.distance);

只要排序是最后一个操作,这应该可以解决运行时问题。

I was under the assumption that it won't be turned into a SQL query and executed until I enumerate the results, which is why I wait until the last line to return the results AsEnumerable(). Is that the correct approach?

是的,这是正确的做法。您希望 RDBMS 做尽可能多的工作,因为在内存中进行分页首先违背了分页的目的。

If I have to enumerate the results before doing Skip and Take how will that affect performance?

这会降低性能,因为与添加分页之前相比,您的系统需要移动更多的数据。

关于c# - 方法 ‘Skip’ 仅支持 LINQ to Entities 中的排序输入。必须在方法 ‘OrderBy’ 之前调用方法 ‘Skip’,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21705926/

相关文章:

c# - Functors() 为类重载

c# - 在 Bouncy CaSTLe 中使用正确的加密服务提供商更新 x509Certificate2

c# - 将存储在整数列表(小端)中的二进制表示形式转换为 Biginteger

c# - 使用 ManagedInterop 从 C# 中删除记录

c# - 包含关键字的 Linq 不同记录

asp.net-mvc - LINQ - OrderBy 的动态表达式

linq 在 null 上加入

c# - 是否可以在 Visual Studio Express 版本中将 Entity Framework 与 MySQL 一起使用?

c# - Entity Framework 6 单元测试 (NSubstitute) - 如何测试带有子对象的对象在未请求子对象时不返回子对象

c# - Entity Framework 性能问题