但若果轉移到LINQ上,或許會感到迷惑,因為寫SQL都久了,把SQL語法的直覺性放在LINQ可是不行。
聽起來很抽象吧? 來看看示範
以AdventureWorks 2008 LT Sample DB 配合 LINQPad做示範。
我想找出SalesOrderID : 71920的貨物總和/價值總和,SQL就很容易會寫出這樣,亦得出正確的結果。
SELECT SalesOrderID, SUM(OrderQty) as TotalQty, SUM(UnitPrice) as TotalPrice FROM SalesLT.SalesOrderDetail detail WHERE detail.SalesOrderID = '71920' GROUP BY detail.SalesOrderID;
來到LINQ,如果把SQL的編寫概念放在LINQ,或許你會跟我一樣寫出 :
from detail in SalesOrderDetails where detail.SalesOrderID.Equals(71920) group detail by detail.SalesOrderID into g select g
但當然,結果是怪怪的。
得出來的是 IOrderedQueryable<IGrouping<Int32,SalesOrderDetail>>
因為在這裡的Group...By...其實只是意味著把SalesOrderID和SalesOrderDetail集合至IGrouping的"g"。
結果其實與下方Comment的差不多。
正確的寫法應該是用new keyword去建立新的class。
from detail in SalesOrderDetails where detail.SalesOrderID.Equals(71920) group detail by detail.SalesOrderID into g select new { /*Distinct() return Enumerable<Int32> , Sum() & First() to return Int32 */ SalesOrderID = g.Select(item =>item.SalesOrderID).Distinct().First(), TotalQty = g.Select(item =>Convert.ToDouble(item.OrderQty)).Sum(), TotalPrice = g.Select(item =>item.UnitPrice).Sum() }
上述的new keyword跟平時的功用相似 ( FileInfo fInfo = new FileInfo(); ),但在這裡是建立新的Class或Structs,而且是Anonymous Type,帶有SalesOrderID / TotalQty / TotalPrice 的Properties。
得出來的結果就會是 :
如果覺得語法太冗長,可以改寫成Method-Based的Syntax :
SalesOrderDetails.Where(sod => sod.SalesOrderID == 71920) .GroupBy(sod => sod.SalesOrderID) .Select(g => new { SalesOrderId = g.Key, TotalQty = g.Sum(i => Convert.ToDouble(i.OrderQty)), TotalPrice = g.Sum(i => i.UnitPrice) })
參考:
Method-Based Query Syntax
http://msdn.microsoft.com/en-us/library/bb669086.aspx
Query Syntax and Method Syntax in LINQ (C#)
http://msdn.microsoft.com/en-us/library/vstudio/bb397947.aspx