2014-02-11 17 views
9

使用实体框架6.0.2.NET 4.5.1的Visual Studio 2013更新1与连接到SQL Server的一个DbContext“跳过”方法仅支持LINQ to Entities中的排序输入。该方法 '排序依据' 必须调用该方法之前, '跳过'

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

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() }; 

现在我的问题(S):

  1. 正如你所看到的,我在最初的LINQ查询中做了order by,所以wh是否它抱怨我需要做OrderBy之前做一个Skip(我以为我是?)...

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

  3. 如果我必须在做SkipTake之前列举结果,这将如何影响性能?很显然,我想让SQL Server完成繁重的工作,并只返回请求的结果。或者没有关系(或者我错了)?

回答

11

我做在初始LINQ查询的排序依据,那么,为什么抱怨,我需要做一个跳过前做一个排序依据(我想我是?)

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做尽可能多的工作越好,因为在内存中做分页失败分页摆在首位的目的。

如果我在做之前必须列举结果跳过并考虑如何影响性能?

这会导致性能下降,因为系统需要移动更多的数据,而不是添加分页之前。

+0

快速注释:如果您使用的是“开关”语句来处理你的中将sortOrder,请尝试使用“默认”的情况下,将责令你的结果由您选择的字段设置。 – CodeBreaker

相关问题