復合查詢
在前一節中, 我們寫了一個查詢來將分解那些包含一個字母a, 按長度排序, 並且最後轉換成大寫的字符串. 我們還有另外一種復合查詢的寫法:
1: //前面我們使用的寫法
2: string[] names = { "James","Jack","Harris"};
3:
4: IEnumerable<string> query = names.Where(n => n.Contains ("a"))
5: .OrderBy (n => n.Length).Select (n => n.ToUpper( ));
6:
7: //組合查詢的寫法
8: string[] names = { "James","Jack","Harris"};
9: IEnumerable<string> q = from n in names where n.Contains("a")
10: orderby n.Length
11: select n.ToUpper();
12:
13: foreach(string s in q)
14: Console.Write(s + ","); //JACK,JAMES,HARRIS,
一個復合查詢總是開始於from語句結束於select或者group語句. from語句聲明了一個迭代變量, 此變量代表輸入序列中的每一個元素, 類似foreach語法中的變量. 編譯器會將復合查詢翻譯成Lambda表達式, 類似於foreach表達式會被翻譯成調用GetEnumerator和MoveNext方法. 這意味著任何你可以使用的復合查詢同樣也可以使用Lambda表達式來完成. 例如上面的例子, 編譯器將會翻譯成這樣:
1: IEnumerable<string> q = names
2: .Where(n => n.Contains ("a"))
3: .OrderBy(n => n.Length)
4: .Select(n => n.ToUpper());
迭代變量
緊跟在from關鍵字之後的標識符稱為迭代變量, 在我們的例子中, 迭代變量n出現在每一個查詢中的每一個從句. 然後, 此變量實際上枚舉了每一個從句中的不同序列中的元素:
1: from n in names // n 是我們的迭代變量
2: where n.Contains ("a") // n = 直接來自於數組
3: orderby n.Length // n = 被過濾後的
4: select n.ToUpper(); // n = 排序過的
如果檢查一下編譯器幫我們生成的使用Lambda表達式的版本就可以看得更加清晰一點:
1: names.Where (n => n.Contains ("a"))
2: .OrderBy (n => n.Length)
3: .Select (n => n.ToUpper());
n都是只屬於各自Lambda表達式的范圍裡面的.
查詢語法 VS SQL語法
LINQ的復合查詢語法看起來和SQL語法非常像, 然後他們是非常不同的. 一個LINQ查詢說到底還是一個C#表達式, 因為必須要遵循標准的C#規則. 例如, 在LINQ中, 你不能使用一個未聲明的變量. 而在SQL中, 在from語句定義之前你已經可以在select中引用一個表的別名了.
在LINQ中的子查詢僅僅是另外一個C#表達式, 因此並不需要有什麼特殊的語法. 而子查詢在SQL當中通常要受到一些特殊規則的限制.
在LINQ中, 整個數據處理流程是從左到右的. 而在SQL中, 這個順序則更加隨機.
一個LINQ查詢構成一個傳送帶, 或者一個管道, 其中的操作符接受和處理有序序列. 而SQL查詢則構成的語法網更多的是處理無序集合.
查詢語法和 Lambda表達式
復合查詢和Lambda表達式語法更有優點. 復合查詢對於符合以下情況的查詢更加簡單一些:
1. let從句來一個迭代變量後用於代表一個新的變量
1: var list = new List<int>() { 1, 2, 3 };
2: var query = from i in list
3: let j = i + 2
4: let k = j * j
5: select new { i, j, k };
2. SelectMany, Join或者GroupJoin緊跟著一個外部的迭代變量引用
至於Where, OrderBy和Select的使用, 兩種表達語法都可以工作的很好, 如何使用, 更多的取決於個人習慣.
對於那些只由單一操作符構成的查詢來說, Lambda表達式語法更加簡短,簡潔一點.
最後, 有很多的操作符是沒有對應的復合查詢關鍵字的, 對於這些操作符你只能使用Lambda表達式語法, 或者至少部分使用, 它們是:
Where, Select, SelectManager, OrderBy, ThenBy, OrderByDescending, ThenByDescending, Group, Join, GroupJoin
混合的查詢語法
如果一個查詢操作符沒有對應的復合查詢支持, 你可以混合使用復合查詢和Lambda表達式語法. 唯一的限制是每一個復合組件都必須被完成(例如從一個form從句開始並且結束於一個select或者group從句).
例如:
1: string[] names = { "James","Jack","Harris"};
2: int myCount = (from n in names
3: where n.Contains ("J")
4: select n
5: ).Count();
6: Console.WriteLine(myCount); //2
有一點是非常重要的, 你不能單一的偏向於喜歡復合查詢語法或者Lambda表達式語法, 更多的應該是根據功能的需要和簡單性來做選擇. 待續!