只有LINQ to Entities中的排序输入才支持’Skip’方法。 必须在方法’Skip’之前调用’OrderBy’方法

使用连接到SQL Server的DbContextVisual Studio 2013 Update 1中使用Entity Framework 6.0.2.NET 4.5.1

我有一长串filter,我根据调用者的期望结果应用于查询。 一切都很好,直到我需要添加分页。 这是一瞥:

 IQueryable results = (from pl in db.ProviderLocations let distance = pl.Location.Geocode.Distance(_geo) where pl.Location.Geocode.IsEmpty == false where distance  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 _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 _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 _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. 如果我必须在Skip之前枚举结果并Take如何影响性能? 显然,我希望SQL Server能够完成繁重的任务并仅返回请求的结果。 或者没关系(或者我弄错了)?

我在最初的LINQ查询中做了一个orderby,所以为什么在做Skip之前我需要做一个OrderBy(我以为我是?)

您的result作为有序可查询项正确启动:从第一行查询返回的类型是IOrderedQueryable ,因为您有一个order by子句。 但是, Where上添加Where会使您的查询再次成为普通的IQueryable ,从而导致您看到的问题。 从逻辑上讲,这是一回事,但内存中查询定义的结构意味着其他方面。

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

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

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

我假设它不会被转换为SQL查询并执行,直到我枚举结果,这就是为什么我等到最后一行返回结果AsEnumerable() 。 这是正确的方法吗?

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

如果我必须在跳过之前枚举结果并采取如何影响性能?

它会破坏性能,因为系统需要移动比添加分页之前更多的数据。