如果始终在本地评估跳过和获取,如何在 EF Core 中运行分页查询?



我有一个 ASP.NET 核心Web API,它使用实体框架核心(版本2.0.2(返回名为PhotoAlbum的数据模型的分页列表。为此,它会构建如下IQueryable<PhotoAlbum>

var query = _context.PhotoAlbums
.Include(album => album.SpotlightPhotoView)
.ApplySecurity(user)
.ApplyFilter(filter)
.Sort(sortInfo);

其中ApplySecurityApplyFilterSort是我自己的扩展,分别应用两个Where过滤器和一个OrderBy过滤器。最后,代码使用SkipTake返回匹配数据的特定子集。

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

无法翻译 LINQ 表达式"Take(__p_2(",将在本地进行计算。

无法翻译 LINQ 表达式"Skip(__p_1(",将在本地进行计算。

LINQ 表达式"其中 [专辑]。精选"'无法翻译,将在本地进行评估。

LINQ 表达式 '" where (([album].Complete OrElse False( OrElse False("' 无法翻译,将在本地进行评估。

阅读这些警告后,我现在知道 EF Core 中的某些 Linq 方法无法转换为 SQL。其中包括聚合函数,如SumCount以及SkipTake

所以我的第一个问题是:如果你想实现分页查询,推荐的解决方案是什么?存储过程是选项吗?

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

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

query = query.Where(album => album.Featured);

应用[album].Complete过滤器的代码如下所示...

query = query
.Where(album =>
album.Complete || filter.IncludeIncomplete
&& album.Published || filter.IncludeUnpublished);

。其中filter是一个简单的模型,其中包含一组定义如何筛选的布尔属性。

这是根据我的日志执行的实际 SQL(为了可读性,从SELECT中删除了几列(:

SELECT [album].[AlbumID], [album].[AlbumDate], [album.SpotlightPhotoView].[PhotoViewID]
FROM [PhotoAlbum] AS [album]
LEFT JOIN [PhotoView] AS [album.SpotlightPhotoView] ON [album].[SpotlightPhotoViewID] = [album.SpotlightPhotoView].[PhotoViewID]
WHERE ([album].[Complete] = 1) AND ([album].[Featured] = 1)
ORDER BY [album].[AlbumDate] DESC

尽管有警告,它似乎已经很好地应用了FeaturedComplete过滤器。

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

where [album].Featured是另一个可疑的警告。所有版本都绝对支持按布尔属性进行筛选。Featured是否是没有正确配置的计算属性?

除此之外,在最新的LTS(长期支持(版本EF Core 2.1中添加了GROUP BY和聚合函数。

Take and Skip 绝对适用于 EF Core 2.2.6 和 EF Core 3.0 Preview 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

最新更新