文章出處

先解釋一下這個標題的意思,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 代碼,還請指教。


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()