我有一个 ASP.NET 核心Web API,它使用实体框架核心(版本2.0.2(返回名为PhotoAlbum
的数据模型的分页列表。为此,它会构建如下IQueryable<PhotoAlbum>
:
var query = _context.PhotoAlbums
.Include(album => album.SpotlightPhotoView)
.ApplySecurity(user)
.ApplyFilter(filter)
.Sort(sortInfo);
其中ApplySecurity
、ApplyFilter
和Sort
是我自己的扩展,分别应用两个Where
过滤器和一个OrderBy
过滤器。最后,代码使用Skip
和Take
返回匹配数据的特定子集。
我有兴趣在我的日志中看到以下警告:
无法翻译 LINQ 表达式"Take(__p_2(",将在本地进行计算。
无法翻译 LINQ 表达式"Skip(__p_1(",将在本地进行计算。
LINQ 表达式"其中 [专辑]。精选"'无法翻译,将在本地进行评估。
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);
应用[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
尽管有警告,它似乎已经很好地应用了Featured
和Complete
过滤器。
我怀疑自定义方法及其输入生成的表达式无法转换为 SQL。where (([album].Complete OrElse False) OrElse False)
绝对不能 - SQL 中没有OrElse
。OrElse
是一个 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