還記得久遠之前限量的那篇 LINQ to Entities Part I 裡,隔了這麼久,限量才突然想到還有其他的未補完。之前 Part I 已經介紹過了 Select, SelectMany, Where, Distinct, GroupBy, OrderBy, OrderByDescending, Join。Part I 說的全部都是類 SQL 的查詢方法,接下來剩的當然還是有一些類 SQL的方法,中間還穿插了一些特殊用途的方法,那就讓我們繼續往下看下去。
下列是本篇要接下來分析的Extension 方法:
public static TResult Aggregate<TSource, TAccumulate, TResult>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, TResult> resultSelector
)
參數:
上面的SQL使用LIMIT,指的是SELECT出來的結果限制從index 0開始往後算取1筆。看完了First就要提一下他的另一個延伸擴充方法 FirstOrDefault。使用 First 要注意的是必須確定你搜尋出來的結果一定要有資料,不然會丟出InvalidOperationException。然而,使用FirstOrDefault在搜尋結果沒資料時,至少會回傳該集合Type的預設值,例如int就回傳0, string就回傳null,object或其他reference type回傳null。所以如果你不確定回傳的結果有沒有資料的話就建議使用FirstOrDefault。
參考來源:
MSDN - IEnumerable(T) 介面
下列是本篇要接下來分析的Extension 方法:
- Aggregate
- All
- Average
- Count
- Except
- First & FirstOrDefault
- Intersect
- Last & LastOrDefault
- Max
- Min
我們使用的資料和前篇一樣,是一個商品倉儲相關的資料表:
Good
Aggregate
Aggregate是可將集合進行彙總的擴充方法,你可以將彙總規則Func傳入,程式會逐筆執行Func,然後將每次的結果傳給下一輪。此外,在彙總之後還可以再使用另一個Func對彙總後的資料進行處理。以下為MSDN上的Aggregate語法(最複雜的):public static TResult Aggregate<TSource, TAccumulate, TResult>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, TResult> resultSelector
)
參數:
- seed:進行彙總的初始值。
- func:彙總規則的Function,每一輪傳入的參數為 1. 目前彙總值; 2. 目前處理資料。
- resultSelector:對最後彙總結果進行處理的Function,傳入的參數為最後彙總值。
Scenario
在所有Goods裡挑出價格大於8000台幣的資料,然後把價格轉為美金。var expensives = Goods.ToList().Aggregate(new List<Good>(), (gathers, good) => { if(good.Price > 8000) { gathers.Add(good); } return gathers; }, result => { result.ForEach(r => { r.Price = r.Price.Value / 30; }); return result; });
Result
All
All是用來判斷是否集合中的資料都符合塞選的條件。Scenario
判斷是否在Goods中是否所有的商品價格都大於1000元。var isMoreThan1000 = Goods.All(x => x.Price > 1000);
SQL
SELECT COUNT(*) AS [value] FROM [Good] AS t0 WHERE NOT (t0.[Price] > 1000)因為SQL語法中是無法SELECT布林值出來,所以可以用SELECT COUNT的方式來看看是否有不符合的筆數資料,如果結果大於0代表有不符合的資料。
Result
False。從結果來看,因為所有資料中(7筆),有一個商品的價格只有50元,所以並不符合所有都大於1000的假設,故回傳結果為False。Average
Average是用來計算集合中某的欄位的平均值。Scenario
計算Goods中所有商品的價格平均。var average = Goods.Average(x => x.Price);
SQL
SELECT AVG(t0.[Price]) FROM [Good] AS t0
Result
(9999 + 23000 + 19000 + 7000 + 5000 + 1000000 + 50) / 7 = 152007。Count
Count用來計算符合條件的資料筆數。Scenario
計算SalesID為2的資料筆數。var sales2Goods = Goods.Count(x => x.SalesID == 2);
SQL
SELECT COUNT(*) FROM [Good] AS t0 WHERE (t0.[SalesID] = 2
Result
3。我們也可以使用Where的方式取得資料筆數,如下:var sales2Goods = Goods.Where(x => x.SalesID == 2).Count();
Except
Except可用來比較兩組集合的差異元素並回傳差異元素集合(注意: )。Scenario
有兩個List,aList為Goods所有商品中價格大於5000的商品集合;bList為Goods所有商品中SalesID為2的商品集合。接著我們對aList中的商品進行對bList的商品進行排除。var aList = Goods.Where(x => x.Price > 5000); var bList = Goods.Where(x => x.SalesID == 2); var diff = aList.Except(bList);
SQL
SELECT t0.[AddDate], t0.[Description], t0.[ID], t0.[Name], t0.[Price], t0.[SalesID] FROM [Good] AS t0 WHERE ((t0.[Price] > 5000) AND NOT EXISTS( SELECT 0 FROM [Good] AS t1 WHERE ((t1.[SalesID] = 2) AND (t1.[ID] = t0.[ID])) ))
Result
First
取得集合中符合條件的第一筆資料。Scenario
在所有商品中,SalesID為2的共有3筆。3筆依價格高低排序(高順位)後取得最高價格的一筆。var first = Goods.OrderByDescending(x => x.Price).First(x => x.SalesID == 2);
SQL
SELECT t0.[AddDate], t0.[Description], t0.[ID], t0.[Name], t0.[Price], t0.[SalesID] FROM [Good] AS t0 WHERE (t0.[SalesID] = 2) ORDER BY t0.[Price] DESC LIMIT 0, 1
Result
上面的SQL使用LIMIT,指的是SELECT出來的結果限制從index 0開始往後算取1筆。看完了First就要提一下他的另一個延伸擴充方法 FirstOrDefault。使用 First 要注意的是必須確定你搜尋出來的結果一定要有資料,不然會丟出InvalidOperationException。然而,使用FirstOrDefault在搜尋結果沒資料時,至少會回傳該集合Type的預設值,例如int就回傳0, string就回傳null,object或其他reference type回傳null。所以如果你不確定回傳的結果有沒有資料的話就建議使用FirstOrDefault。
Intersect
Intersect是取得兩個集合的所有交集元素。Scenario
在商品價格大於7000(aList)與SalesID為2(bList)的兩個集合中取得交集。var aList = Goods.Where(x => x.Price > 7000); var bList = Goods.Where(x => x.SalesID == 2); var intersect = greaterThan5000.Intersect(salesIdEqualTo2);
SQL
SELECT t0.[AddDate], t0.[Description], t0.[ID], t0.[Name], t0.[Price], t0.[SalesID] FROM [Good] AS t0 WHERE ((t0.[Price] > 7000) AND EXISTS( SELECT 0 FROM [Good] AS t1 WHERE ((t1.[SalesID] = 2) AND (t1.[ID] = t0.[ID])) ))
Result
Last
Last與First功能類似。First是取得集合中的第一筆,反之,Last為取得集合中的最後一筆。Scenario
與First對比,我們就用和First的相同範例進行解說,在所有商品中,SalesID為2的共有3筆。3筆依價格高低排序(高順位)後取得最低價格的一筆。var last = Goods.OrderByDescending(x => x.Price).Last(x => x.SalesID == 2);
SQL
SELECT t0.[AddDate], t0.[Description], t0.[ID], t0.[Name], t0.[Price], t0.[SalesID]
FROM [Good] AS t0
WHERE (t0.[SalesID] = 2)
ORDER BY t0.[Price]
LIMIT 0, 1
Result
從Last Gen出來的SQL和Firt Gen出來的SQL可以看到,兩者在前段其實都差不多,但不同的是,我在Last的Sample Code下的是OrderByDescending,可是Gen出來的SQL竟然是ORDER BY,組合出來的意思是蠻符合邏輯的,但限量還是蠻不解的。
Max
Max功用與SQL語法的Max相同,就是取得集合中某個欄位的最大數值。
Scenario
在所有商品中取得最貴的價格。
var max = Goods.Max(x => x.Price);
SQL
SELECT MAX(t0.[Price]) FROM [Good] AS t0
Result
1000000。
Mix
與Max相對,與SQL語法的Min相同,就是取得集合中某個欄位的最小值。Scenario
在所有商品中取得最便宜的價格。
var min = Goods.Min(x => x.Price);
SQL
SELECT MIN(t0.[Price]) FROM [Good] AS t0
Result
50。
最近實在是幾不太出時間來寫,這篇就花了蠻多時間的,但仔細看完後可以馬上用就感覺不錯。這回還未把剩下的方法全介紹完,所以期待Part III, Part IV...吧。
參考來源:
MSDN - IEnumerable(T) 介面
留言
張貼留言