2

我正在使用实体框架实现服务器端分页并具有以下代码

 DbQuery<T> query = Context.Set<T>();

 query = IncludeNavigationProperties(query, includedProperties);

 var result =  query.OrderBy(arg => arg.DatabaseId)
                    .Skip((pageNumber - 1)*pageSize)
                    .Take(pageSize).ToList();

这会生成一个只查询必要数据的 SQL(使用 SQL Server Profiler 检查)

SELECT TOP (21) 
[Extent1].[DatabaseId] AS [DatabaseId], 
...[other props here]...
FROM ( SELECT [Extent1].[DatabaseId] AS [DatabaseId], ...[other props here]..., row_number() OVER (ORDER BY [Extent1].[DatabaseId] ASC) AS [row_number]
    FROM [dbo].[Table] AS [Extent1]
)  AS [Extent1]
WHERE [Extent1].[row_number] > 84
ORDER BY [Extent1].[DatabaseId] ASC

然后我决定在更多场景中重用这个方法,并keySelector作为外部变量传递:

 DbQuery<T> query = Context.Set<T>();

 query = IncludeNavigationProperties(query, includedProperties);

 var result =  query.OrderBy(keySelector)
                    .Skip((pageNumber - 1)*pageSize)
                    .Take(pageSize).ToList();

在哪里

Func<T, int> keySelector = arg => arg.DatabaseId;

但它突然生成以下 SQL 查询:

SELECT 
[Extent1].[DatabaseId] AS [DatabaseId], 
...[other props here]...
FROM [dbo].[Table] AS [Extent1]

据我了解,它从 Table 中查询所有数据,然后在服务器上对其进行处理。

所以,我有两个问题:

  1. 为什么查询会改变?
  2. 我该如何修复它(能够改变keySelector和只查询必要的数据)?
4

1 回答 1

2

DbQuery<T>派生自IQueryable<T>IEnumerable<T>类。这两个类都提供OrderBy了一个不同的方法:OrderByonIEnumerable获取 aFunc<T1,T2>OrderByonIQueriable获取Expression<Func<T1,T2>>参数。当你keyselector作为Func<T1,T2>对象传递给OrderBy方法时,你告诉编译器:嘿!请使用OrderBy上定义的方法IEnumerable换句话说,您的DbQuery<T>对象被强制转换为IEnumerable<T>notIQueriable<T>.这就是为什么所有数据都被提取到客户端并且进一步的操作在内存中完成的原因。

要解决此问题,请将keyselectorfrom的类型Func<T1,TKey>更改Expression <Func<T1,TKey>>为:

public IQueriable<T> YourMethodName<T, TKey>(Expression<Func<T,TKey>> keyselector)
{
    DbQuery<T> query = Context.Set<T>();

     query = IncludeNavigationProperties(query, includedProperties);

     var result =  query.OrderBy(keySelector)
                        .Skip((pageNumber - 1)*pageSize)
                        .Take(pageSize).ToList();
     return result;
}
于 2013-09-23T13:47:28.550 回答