C# 如果Skip和Take总是在本地计算,如何在EF Core中运行分页查询?

C# 如果Skip和Take总是在本地计算,如何在EF Core中运行分页查询?,c#,linq,entity-framework-core,C#,Linq,Entity Framework Core,我有一个ASP.NET Core Web API,它使用Entity Framework Core(版本2.0.2)返回名为PhotoAlbum的数据模型的分页列表。为此,它构建了一个IQueryable,如下所示: var query = _context.PhotoAlbums .Include(album => album.SpotlightPhotoView) .ApplySecurity(user) .ApplyFilter

我有一个ASP.NET Core Web API,它使用Entity Framework Core(版本2.0.2)返回名为
PhotoAlbum
的数据模型的分页列表。为此,它构建了一个
IQueryable
,如下所示:

    var query = _context.PhotoAlbums
        .Include(album => album.SpotlightPhotoView)
        .ApplySecurity(user)
        .ApplyFilter(filter)
        .Sort(sortInfo);
其中
ApplySecurity
ApplyFilter
Sort
是我自己的扩展,分别应用两个
Where
过滤器和一个
OrderBy
过滤器。最后,代码使用
Skip
Take
返回匹配数据的特定子集

我有兴趣在我的日志中看到以下警告:

无法翻译LINQ表达式“Take(u p_2)”,将在本地对其求值

无法翻译LINQ表达式“Skip(u p_1)”,将在本地计算

无法翻译LINQ表达式“where[album].Featured”,将在本地进行计算

无法翻译LINQ表达式“where(([album].Complete OrElse False)OrElse False)”,将在本地对其求值

读了这些警告之后,我现在知道EF Core中的某些Linq方法无法转换为SQL。这些函数包括聚合函数,如
Sum
Count
以及
Skip
Take

因此,我的第一个问题是:如果要实现分页查询,建议的解决方案是什么?存储过程是选项吗?

我的第二个问题是:为什么在
Where
子句周围有警告?

为了说明第二个问题,应用
[album].Featured
过滤器的代码如下所示

    query = query.Where(album => album.Featured);
    query = query
        .Where(album =>
            album.Complete || filter.IncludeIncomplete
            && album.Published || filter.IncludeUnpublished);
应用
[album].Complete
筛选器的代码如下所示

    query = query.Where(album => album.Featured);
    query = query
        .Where(album =>
            album.Complete || filter.IncludeIncomplete
            && album.Published || filter.IncludeUnpublished);
…其中,
filter
是一个简单的模型,具有一组定义如何过滤的布尔属性

下面是根据我的日志执行的实际SQL(为了可读性,从
SELECT
中删除了一些列):


它似乎已经应用了
特色
完整
过滤器,尽管有警告。

我怀疑自定义方法及其输入生成的表达式无法转换为SQL
where(([album].Complete-OrElse-False)OrElse-False)
绝对不能-SQL中没有
OrElse
OrElse
是一个VB.NET关键字

where[album].Featured
是另一个可疑警告。所有版本都明确支持按布尔属性过滤。
功能化
可能是没有正确配置的计算属性吗

除此之外,还添加了GROUP BY和AGGRATE函数,这是最新的LTS(长期支持)版本

选择并跳过EF Core 2.2.6和EF Core 3.0预览版8中的工作。在LinqPad 6中尝试此查询:

Posts.OrderBy(p=>p.PostId).Skip(100).Take(100)
生成此SQL查询:

SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[Title]
FROM [Posts] AS [p]
ORDER BY [p].[PostId]
OFFSET @__p_0 ROWS FETCH NEXT @__p_0 ROWS ONLY

您使用的是哪个EF核心版本?早期的EF核心版本并没有实现每个LINQ操作符,而是使用局部求值。EF Core 3已禁用此功能。您是否尝试过在一个简单的LINQ查询中使用
Skip()
Take()
?那些过滤器是什么?如果其中任何一个使用了无法转换为SQL的表达式,则必须在本地计算整个查询。关于[album].Featured的警告也很奇怪-这是本地计算的属性吗?无法在服务器上对其进行评估,因为服务器不知道
功能的公式是什么
isBTW
这些公式包括聚合函数,如Sum和Count以及Skip和Take。
这对聚合不适用,因为它是最新的LTS(长期支持)版本。您使用的是早期的、可能不受支持的版本吗?顺便说一句,我无法在LinqPad中重现EF 2.2.6或EF Core 3 Preview 8的任何问题。在这两种情况下,查询
Posts.OrderBy(p=>p.PostId).Skip(100).Take(100)
结果是
OrderBy[p].[PostId]OFFSET\u p\u 0行仅获取下一个\u\u p\u 0行
所有LINQ函数都可以转换为SQL。这是他们的主要目的之一,其中包括
Skip
Take
。在
ApplySecurity
ApplyFilter
Sort
后面张贴代码。您可能在那里做了一些奇怪的事情,导致了这个问题。LINQ查询表达式中的
OrElse
不是VB关键字,而是表示逻辑OR的表达式(C#
| |
,VB
OrElse
运算符)-。因此,它肯定受到支持并被转换为SQL
。客户机评估很可能是由于有问题的
条件的2.0.2翻译中的缺陷/bug造成的。当然,
的客户端评估,其中
自动意味着下一个操作符的客户端评估,如
跳过
接受