換一種寫作風格。本節講groupby操作。
在所有的Linq To Sql操作中,GroupBy是最難理解的一個。因為,這裡和Sql的出入較大。而Group真的就能返回n多組。
打開vs,新建一工程,加入System.Data.Linq.dll的引用。把northwind數據庫做個映射,添加到工程裡。創建一Northwind類的對象。在這裡呢,我們要做分組統計,我們要先明白什麼是分組。在我們開始設計product表時,我們欲留了一列叫做CategoryID。 這個字段,代表了這條記錄中的產品,歸屬於那個類別。如圖,字段的設計。
可以簡單的舉例,比如,當CategoryID的值為1時,就表示,對應的記錄的產品是飲料類的。當它為2時,代表調味品類的。具體代表那一類,要看事先的約定。一般會專門有個表來保存這個約定。在northwind中,用Categories 表來保存這個約定。下面是catagories表中的紀錄。
Categories 和Product表,通過CategoryID字段關聯關系。也就是說,Product表中,CategoryID字段所代表的意思,保存在Categories 表中。好了,知道分組的概念了,我們開始分類統計吧。在Linq To Sql的所有操作中,groupby算是比較難理解的一個。我要友好的提醒你注意下這裡的分組所用的字段哦,這個將來是要被用做繼承的哦。
我們來看下面的例子。
var q =
from p in db.Products
group p by p.CategoryID into g
select g;
在這裡,from p in db.Products表示從表中將對象紀錄取出來。p就是每一個產品。而後面一句,group p by p.CategoryID into g表示對p進行歸類,按什麼歸類呢,就是要按我們設定的CategoryID這個字段。而這個歸類的結果,被重新命名為g,而且是必須重新命名。一旦重新命名,p的作用域就結束了,所以,最後select時,只能select g。
那有人就要問了,不重新命名可以嗎?回答,可以。那你的select語句就沒有了,上面語句等同與
var q = from p in db.Products
group p by p.CategoryID;
這是query表達式中,很少見的沒有select語句的情況。我記憶中,好像只有此一種。我們還是按
var q =
from p in db.Products
group p by p.CategoryID into g
select g;
來講解。因為這種更好理解。在T-Sql中,groupby只是用來做分組統計,計算平均值,最大值,求和等等,而在dlinq中的groupby,則發揮到了極值。我們用ToList()取到結果,來看看上面語句返回的結果。如圖:
整個查詢語句返回八個組,這和我們數據庫的八種產品是對應的。找到最後一個group,點開+號,我們可以看到,裡面有個Key和Results View字段,其中Key為8,是數據庫裡對應的Seafood分類,點開Results View你會驚奇的發現,所有的Seafood都在裡面。我們把代碼改一下,看看dlinq究竟做了什麼。
Northwind db = new Northwind(ConStr);
db.Log = Console.Out;
Query#region Query
var q = from p in db.Products
group p by p.CategoryID into g
select g;
#endregion Query
Verification#region Verification
foreach (var gp in q)
}
return;
#endregion Verification{
單步調試該foreach段代碼,foreach的目的是讓dlinq加載數據。在console windows上,你可以看到如下輸出。
SELECT [t0].[CategoryID] AS [Key]
FROM [Products] AS [t0]
GROUP BY [t0].[CategoryID]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 2.0.20612.0
SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID
], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnO
rder], [t0].[ReorderLevel], [t0].[Discontinued]
FROM [Products] AS [t0]
WHERE ((@x1 IS NULL) AND ([t0].[CategoryID] IS NULL)) OR ((@x1 IS NOT NULL) AND
([t0].[CategoryID] IS NOT NULL) AND (@x1 = [t0].[CategoryID]))
-- @x1: Input Int32 (Size = 0; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 2.0.20612.0
原來dlinq不僅僅是做了一個groupby操作呀,他還針對每個組,都去做了一個遍歷呀。我們可以用下面的圖來理解。
外面的大圈,表示全集。而這個全集被分成了若干個小的集合。每個集合就叫做g。在g集合中,包含一個系統定義的Property,叫做Key。key值實際為分類時所用字段的值。而另外一部分,是該類別中所有的product.所以,我們如果想遍歷某類別中所有的紀錄,要這麼來做。
var q = from p in db.Products
group p by p.CategoryID into g
select g;
foreach (var gp in q)
{
if (gp.Key == 7)
{
foreach (var p in gp)
{
//do something
}
}
}