只有LINQ to Entities中的排序输入才支持方法"Skip".方法"OrderB



Visual Studio 2013 Update 1中使用Entity Framework 6.0.2.NET 4.5.1DbContext连接到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,那么为什么它抱怨我需要在执行Skip之前执行OrderBy(我以为我是?)。。。

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

  3. 如果在执行SkipTake之前必须枚举结果,这将如何影响性能?显然,我希望SQL Server能够完成繁重的工作,并且只返回请求的结果。或者这没关系(或者我弄错了)?

我在最初的LINQ查询中执行orderby,为什么它抱怨我需要在执行Skip之前执行orderby(我以为我是?)

您的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);

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

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

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

如果在执行Skip和Take之前必须枚举结果,这将如何影响性能?

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

相关内容

最新更新