2014年4月22日 星期二

練習題 - LINQ Single Column Dynamic Group

這一次要練習的題目是怎麼作到動態選擇欄位做 LINQ 的 Group 操作,其實很少遇到需要在 LINQ 裡做動態 Group 的需求,所以就當做練習題目來練練看。

使用環境:VS2013, ASP.NET MVC 5, EntityFramework 6.1.0

使用資料庫:Northwind


這次練習題所使用的是 Northwind 資料庫,然後用 Product 資料表來做練習,以下的幾個操作都會以 CategoryID 欄位做為 Group 的 Key。

 

操作一

這個操作是參考 MSDN 論壇裡一則討論的解答,

http://forums.asp.net/t/1959786.aspx?how+to+forumulat+a+query+in+dynamic+linq

參考標示解答的作法,將程式寫出來,如下:

image

執行結果

image

T-SQL

image

所使用的是 LambdaExpression 以及 ParameterExpression 的應用

MSDN - LambdaExpression 類別 (System.Linq.Expressions)

MSDN - ParameterExpression 類別 (System.Linq.Expressions)

 

操作二

這次的操作以上面的操作內容一樣,不過差別在於我們將其中建立 ParameterExpression 與 LamdaExpression 的部份抽出來,另外建立一個方法。

參考連結:

http://stackoverflow.com/questions/17678197/linq-grouping-dynamically

image

執行結果

image

T-SQL

image

從 T-SQL 的內容可以看出操作二所使用的方式並非在 SQL Server 裡先做好 Group 的處理,而是將全部資料取回之後再處理 Group。

 

操作三

有鑑於操作二所執行的 Group 處理並非是在 SQL Server 裡,我們再把操作一的程式拿來做個調整,將建立 selector LambdaExpression 的步驟給抽出來然後另外建立方法,

image

就不看執行結果了,直接觀察 T-SQL,

SNAGHTML339831d

所產生並執行的 T-SQL 與操作一的是相同的。

 

操作四

還有另外一種做法,是參考以下連結的作法,

http://stackoverflow.com/questions/3886204/dynamically-adding-a-groupby-to-a-lamba-expression

有別於操作二與操作三的方法,操作二、三是產生 GroupBy 的 Expression 內容,而現在這個方法則是傳入 IQueryable<T> 與欄位名稱,回傳 IQueryable<T> 結果,如下:

image

T-SQL

SNAGHTML3ce52c2

 

操作五

以前曾經有介紹過 DynamicQuery(Dynamic Expression API),所以在這裡也嘗試使用 DynamicQuery 來做單欄位的動態 Group 操作,DynamicQuery 可以經由 NuGet 安裝到專案中。

image

可是這樣的操作會有個問題,那就是因為使用 DynimicQuery 查詢,而我們最後的 Select 又是使用動態的方式(不是強型別)去指定回傳的結果,所以無法在 foreach 迴圈當中取得我們所要的值,將結果裡的資料轉成字串然後輸出到頁面上,可以看到呈現的結果確實是我們所要的 Group 結果,

執行結果

image

T-SQL

image

 

但我還是希望能夠將 DynamicClass 的結果轉成一個物件,所以就建立了一個 GroupResult 的類別,

image

然後我使用 JSON.NET 的功能將查詢結果先序列化轉為 JSON 字串,然後再使用反序列化轉為剛才所建立的 GroupResult 物件,以下是修改後的程式內容,

image

執行結果

image

 

這就是對於在使用 LINQ 做單一個欄位的動態 Group 操作的幾個練習,相信應該還會有更好的方法,也請各位朋友一起討論。


 

以上

2 則留言:

  1. 讚!解決我多年的困惑!
    高手!

    回覆刪除
    回覆
    1. 過獎過獎,都是網路蒐羅來的方法,
      最後一個方式則是跟朋友討論而來的結果。

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。