• EntityFramework 7 OrderBy Skip Take-计算排序分页 SQL 翻译


    先解释一下这个标题的意思,OrderBy 在 Linq 语句中,我们经常使用,比如 OrderBy(b => b.BlogId) 就是对 BlogId 字段进行升序排序,这是针对一个字段的排序,如果多个字段排序,我们可以使用 ThenBy,或者直接在 OrderBy 中对多个字段进行逗号分割,但有一种场景是,我们要对 OrderBy 增加计算功能,什么意思呢?看一段 SQL 代码:

    SELECT [b].[BlogCateId], [b].[BlogId], [b].[Url]
    FROM [Blog] AS [b]
    ORDER BY ([b].[BlogId] * 2 + [b].[BlogCateId])
    OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
    

    这篇博文的主题,其实就是如何用 Linq 翻译这段 SQL 代码,上面这段代码在 SQL Server 中执行没有任何问题,有人说了,很简单啊,比如翻译后的一段代码:

    [Fact]
    public void ContextLoad_Test()
    {
        using (var context = new BloggingContext())
        {
            var query = from b in context.Blogs
                        orderby  b.BlogId * 2 + b.BlogCateId
                        select b;
            var result = query.Skip(0).Take(100).ToList();
        }
    }
    

    没错,最“直白”的翻译就是这样的,但测试运行后会抛出异常:

    异常信息:A query containing the Skip operator must include at least one OrderBy operation.

    这段异常信息大概是说使用 Skip 包含至少一个 OrderBy,也就是说我们上面使用 orderby b.BlogId * 2 + b.BlogCateId + 34,这段代码并没有起到什么效果,或者说 EF 没有识别出来,总的来说我们这些翻译的 Linq 语句是错误的,但很奇怪的是,我使用 Google 搜索这段异常信息,居然没有搜索到任何的相关信息,难道没有人遇到这个异常?还是我的写法有问题?Skip 是 Linq 分页的关键字,上面报错也是针对 Skip 的,如果我们把 Skip 去掉会怎样呢?

    可以看到,我们不使用 Skip,只是使用 Take 进行 Top 查询,是没有任何问题的,还有个问题是,如果使用“计算”性质的 OrderBy,不管是 SQL Server Profiler,还是 EF7 Log 都捕获不到计算的表达式,比如上面的 Take 查询代码,使用 SQL Server Profiler,最后捕获到的 SQL 代码为:

    你会看到,居然连 OrderBy 也没有了,不知道是什么原因?前几天也遇到这样类似一个问题:EntityFramework 7 smallint short 奇怪问题(已解决),主要是使用 short where 查询,没有捕获到,最后发现是 Linq 写法问题,应该使用 equals 进行判断,现在发现这两个问题比较相似,郁闷的是,不知道这个 Linq 该如何翻译。

    上面这样方式行不通,自己也没有头绪,然后就在 Google 上搜各种关键词,比如:linq orderby math skip,linq calculate math skip 等等,但都尝试了下,还是不行,给出几个参考资料:

    网上关于 OrderBy 计算排序的资料,大部分是关于计算排序后获取 Count,然后再进行分组查询出来,比如这段 Linq 代码:

    var query = from p in yourContext.Activation_Details
                group p by new
                {
                    ProductVersion = p.ProductVersion,
                    ProductID = p.ProductID,
                    SubProductID = p.SubProductID
                }
                into pgroup
                let count = pgroup.Count()
                orderby count
                select new
                {
                    Count = count,
                    ProductVersion = pgroup.Key.ProductVersion,
                    ProductID = pgroup.Key.ProductID,
                    SubProductID = pgroup.Key.SubProductID
                };
    

    但这不是我想要的,花了很多时间也没有找到正确的解决方式,最后换一种思路去思考这个问题,如果 OrderBy 在 Linq 中不能进行计算排序,那就针对这个排序计算进行“翻译”,什么意思呢?比如一开始的 ORDER BY ([b].[BlogId] * 2 + B.BlogCateId),其实就是对两个字段进行组合排序,一个是对 BlogId 进行翻倍,然后再加上 BlogCateId 的值,换一种方式其实也是可以的,比如下面这段代码:

    var result = context.Blogs.OrderBy(b => b.BlogId * 2).ThenBy(b => b.BlogCateId).Skip(0).Take(100).ToList();
    

    执行结果:

    不知道这样的写法和一开始上面的 SQL 是不是一样的效果,如果你有更好的“翻译” Linq 代码,还请指教。

  • 相关阅读:
    vue路由传参页面刷新参数丢失问题解决方案
    理解MVC,MVP 和 MVVM
    HTTPS用的是对称加密还是非对称加密?
    元素显示隐藏的9种思路
    CSS中层叠上下文
    DOM盒模型和位置 client offset scroll 和滚动的关系
    css重点知识和bug解决方法
    你可能不知道的CSS
    如何在 React 中优雅的写 CSS?
    html5不常用标签应用场景
  • 原文地址:https://www.cnblogs.com/xishuai/p/ef7-orderby-thenby-skip-take-math.html
Copyright © 2020-2023  润新知