一. 第一個LINQ查詢
1. Language Integrated Query(LINQ)
示例
A. 創建一個控制臺程序
B. 打開主源文件PRogram.cs
C. Visual C# 2010默認在Program.cs中包含Linq名稱空間
using System; using System.Collections.Generic; using System.Linq; using System.Text;
D. 在Program.cs的Main()方法中添加如下代碼
static void Main(string[] args) { string[] names = { "Alonso", "Zheng", "Smith", "Jones", "Smythe", "Small", "Ruiz", "Hsieh", "Jorgenson", "Ilyich", "Singh", "Samba", "Fatimah" }; var queryResults = from n in names where n.StartsWith("S") select n; Console.WriteLine("Names beginning with S:"); foreach (var item in queryResults) { Console.WriteLine(item); } Console.Write("Program finished, press Enter/Return to continue:"); Console.ReadLine(); }
E. 運行即可
2. 用var關鍵字聲明結果變量
var queryResults =
queryResult名稱是隨意指定的,可以把結果命名為任何名稱
var關鍵字告訴C#編譯器,根據查詢推斷結果的類型。這樣,就不必提前聲明從LINQ查詢返回的對象類型了——編譯器會推斷出該類型
3. 指定數據源:from子句
from n in names
指定要查詢的數據
LINQ數據源必須是可枚舉的——即必須是數組或集合,以便從中選擇出一個或多個元素
4. 指定添加:where子句
where n.StartsWith("S")
指定查詢的條件
可以在where子句中指定能應用于數據源中各元素的任意布爾(true 或false)表達式
還可以指定其它條件,例如,長度超過10,where n.Length > 10 或者包含Q,where n.Contains("Q")
where子句是可選的,甚至可以忽略,但在大多數情況下,都要指定where條件
5. 指定元素select子句
select n;
指定結果集中包含哪些元素
select子句是必須的,因為必須指定結果集中有哪些元素
6. 完成:使用foreach循環
Console.WriteLine("Names beginning with S:");
foreach (var item in queryResults) { Console.WriteLine(item); }
用foreach語句迭代結果
7. 延遲執行的查詢
foreach 結構并不是LINQ的一部分,但它是實際執行LINQ查詢的代碼,迭代結果
查詢結果變量僅保存了執行查詢的一個計劃,在訪問查詢結果之前,并沒有提取LINQ數據,這稱為查詢的延遲執行或遲緩執行
二. 使用LINQ方法語法
1. 前面的示例是用LINQ查詢語法編寫的,下一個示例是用LINQ的方法語法(也稱為顯式語法))編寫的相同程序。
2. 查詢語法和方法語法
建議盡量使用查詢語法,僅在需要時使用方法語法。
大多數使用方法語法的LINQ方法都要求傳送一個方法或函數,來計算查詢表達式。
方法/函數參數以委托的形式傳送,它一般引用一個匿名方法。
3. 使用LINQ方法語法的示例
A. 創建一個新的控制臺程序
B. 在Program.cs的Main()方法中添加代碼
static void Main(string[] args) { string[] names = { "Alonso", "Zheng", "Smith", "Jones", "Smythe", "Small", "Rodriguez", "Hsieh", "Jorgenson", "Ilyich", "Singh", "Samba", "Fatimah" };var queryResults = names.Where(n => n.StartsWith("S")); //Where()方法的調用,而不是查詢表達式Console.WriteLine("Names beginning with S:"); foreach (var item in queryResults) { Console.WriteLine(item); } Console.Write("Program finished, press Enter/Return to continue:"); Console.ReadLine(); }
C. 運行即可
三. 排序查詢結果
1. 給查詢結果排序的示例
A. 創建新的控制臺程序
B. 在Program.cs的Main()方法中添加代碼
static void Main(string[] args) { string[] names = { "Alonso", "Zheng", "Smith", "Jones", "Smythe", "Small", "Ruiz", "Hsieh", "Jorgenson", "Ilyich", "Singh", "Samba", "Fatimah" };var queryResults = from n in names where n.StartsWith("S") orderby n select n; Console.WriteLine("Names beginning with S ordered alphabetically:"); foreach (var item in queryResults) { Console.WriteLine(item); } Console.Write("Program finished, press Enter/Return to continue:"); Console.ReadLine(); }
C. 運行即可
四. orderby 子句
1. orderby n
orderby子句默認為升序(A到Z)
2. orderby n descending
添加descending關鍵字,以便指定降序(Z到A)
這是查詢語法版本
3. orderby n.Substring(n.Length - 1)
要按照姓名中的最后一個字母排序,而不是按一般的字母順序排序
示例的結果運行則會變為
Samba Smythe Smith Singh Small
由于僅考慮最后一個字母,所以在本例中,Smith在Singh的前面。
即排外最后一個字母后,會按照第一個字母第二字母這樣的順序再進行排練
五. 用方法語法排序
1. 用方法語法排序的示例
A. 創建新的控制臺程序
B. 在Program.cs的Main()方法中添加代碼
static void Main(string[] args) { string[] names = { "Alonso", "Zheng", "Smith", "Jones", "Smythe", "Small", "Rodriguez", "Hsieh", "Jorgenson", "Ilyich", "Singh", "Samba", "Fatimah" };var queryResults = names.OrderBy(n => n).Where(n => n.StartsWith("S")); //最簡單的Lambda表達式n => nConsole.WriteLine("Names beginning with S:"); foreach (var item in queryResults) { Console.WriteLine(item); } Console.Write("Program finished, press Enter/Return to continue:"); Console.ReadLine(); }
C. 運行即可
2. 為了給元素逆序排序,可以調用OrderByDescending()方法
var queryResults = names.OrderByDescending(n => n).Where(n => n.StartsWith("S"));
這是方法語法版本
3. 按照每個姓名的最后一個字母排序
var queryResults = names.OrderBy(n => n.Substring(n.Length-1)).Where(n => n.StartsWith("S"));
六. 查詢大型數據集
1. 示例
A. 創建新的控制臺程序
B. 在Program.cs的Main()方法中添加代碼
static void Main(string[] args) { int[] numbers = generateLotsOfNumbers(12345678); var queryResults = from n in numbers where n < 1000 select n ; Console.WriteLine("Numbers less than 1000:"); foreach (var item in queryResults) { Console.WriteLine(item); } Console.Write("Program finished, press Enter/Return to continue:"); Console.ReadLine(); }C. 生成一個隨機列表,添加代碼如下
private static int[] generateLotsOfNumbers(int count) { Random generator = new Random(0); int[] result = new int[count]; for (int i = 0; i < count; i++) { result[i] = generator.Next(); } return result; }
D. 運行即可
七. 聚合運算符
1. 常用聚合運算符如下圖

聚合運算符返回一個簡單的標量類型,而不是一系列結果,所以使用它們會強制立即執行查詢,而不是延遲執行。
2. 示例
A. 創建新的控制臺程序
B. 在Program.cs的Main()方法中添加代碼
static void Main(string[] args) { int[] numbers = generateLotsOfNumbers(12345678); Console.WriteLine("Numeric Aggregates"); var queryResults = from n in numbers where n > 1000 select n ; Console.WriteLine("Count of Numbers > 1000"); Console.WriteLine(queryResults.Count()); // Count()返回查詢結果中的行數,在這個例子中是12 345 671行
Console.WriteLine("Max of Numbers > 1000");
Console.WriteLine(queryResults.Max()); // Max()返回查詢結果中的最大值,在這個例子中是大于20億的一個數2 147 483 591,它非常接近int的最大值(int.MaxValue或2 147 483 647)
Console.WriteLine("Min of Numbers > 1000");
Console.WriteLine(queryResults.Min()); // Min()返回查詢結果中的最小值,在這個例子中是1 034
Console.WriteLine("Average of Numbers > 1000");
Console.WriteLine(queryResults.Average()); // Average()返回查詢結果中的平均值,在這個例子中是1 073 643 807.50298,它非常接近1000到20億的值范圍的中間值。
Console.WriteLine("Sum of Numbers > 1000");
Console.WriteLine(queryResults.Sum(n => (long)n)); // Sum(),在此給Sum()方法調用傳送了Lambda表達式n => (long) n,以獲得所有數字的總和。
Lambda表達式允許把Sum()方法的結果轉換為64位長整數,它可以保存超過13的10次方的數字13 254 853 218 619 179,而不出現溢出。
Console.Write("Program finished, press Enter/Return to continue:"); Console.ReadLine(); }
C. 添加generateLotsOfNumbers()方法
private static int[] generateLotsOfNumbers(int count) { Random generator = new Random(0); int[] result = new int[count]; for (int i = 0; i < count; i++) { result[i] = generator.Next(); } return result; }
D. 運行即可
八. 查詢復雜的對象
1. 示例
A. 創建一個新的控制臺程序QueryComplexObjects
B. 給Customer類添加如下的簡短類定義
class Customer { public string ID { get; set; } public string City { get; set; } public string Country { get; set; } public string Region { get; set; } public decimal Sales { get; set; } public override string ToString() { return "ID: " + ID + " City: " + City + " Country: " + Country + " Region: " + Region + " Sales: " + Sales; } }
C. 在Program.cs的Main()方法中添加代碼
static void Main(string[] args) { List <Customer> customers = new List<Customer> { new Customer { ID="A", City="New York", Country="USA", Region="North America", Sales=9999}, new Customer { ID="B", City="Mumbai", Country="India", Region="Asia", Sales=8888}, new Customer { ID="C", City="Karachi", Country="Pakistan", Region="Asia", Sales=7777}, new Customer { ID="D", City="Delhi", Country="India", Region="Asia", Sales=6666}, new Customer { ID="E", City="S?o Paulo", Country="Brazil", Region="South America", Sales=5555 }, new Customer { ID="F", City="Moscow", Country="Russia", Region="Europe", Sales=4444 }, new Customer { ID="G", City="SEOul", Country="Korea", Region="Asia", Sales=3333 }, new Customer { ID="H", City="Istanbul", Country="Turkey", Region="Asia", Sales=2222 }, new Customer { ID="I", City="Shanghai", Country="China", Region="Asia", Sales=1111 }, new Customer { ID="J", City="Lagos", Country="Nigeria", Region="Africa", Sales=1000 }, new Customer { ID="K", City="Mexico City", Country="Mexico", Region="North America", Sales=2000 },
new Customer { ID="L", City="Jakarta", Country="Indonesia", Region="Asia", Sales=3000 }, new Customer { ID="M", City="Tokyo", Country="Japan", Region="Asia", Sales=4000 }, new Customer { ID="N", City="Los Angeles", Country="USA",
Region="North America", Sales=5000 }, new Customer { ID="O", City="Cairo", Country="Egypt", Region="Africa", Sales=6000 }, new Customer { ID="P", City="Tehran", Country="Iran", Region="Asia", Sales=7000 }, new Customer { ID="Q", City="London", Country="UK", Region="Europe", Sales=8000 }, new Customer { ID="R", City="Beijing", Country="China", Region="Asia", Sales=9000 }, new Customer { ID="S", City="Bogotá", Country="Colombia", Region="South America", Sales=1001 }, new Customer { ID="T", City="Lima", Country="Peru", Region="South America", Sales=2002 } }; var queryResults = from c in customers where c.Region == "Asia" select c ; Console.WriteLine("Customers in Asia:"); foreach (Customer c in queryResults) { Console.WriteLine(c); }
Console.Write("Program finished, press Enter/Return to continue:"); Console.ReadLine(); }
D. 運行即可,結果是來自亞洲的顧客列表
Customers in Asia: ID: B City: Mumbai Country: India Region: Asia Sales: 8888 ID: C City: Karachi Country: Pakistan Region: Asia Sales: 7777 ID: D City: Delhi Country: India Region: Asia Sales: 6666 ID: G City: Seoul Country: Korea Region: Asia Sales: 3333 ID: H City: Istanbul Country: Turkey Region: Asia Sales: 2222 ID: I City: Shanghai Country: China Region: Asia Sales: 1111 ID: L City: Jakarta Country: Indonesia Region: Asia Sales: 3000 ID: M City: Tokyo Country: Japan Region: Asia Sales: 4000 ID: P City: Tehran Country: Iran Region: Asia Sales: 7000 ID: R City: Beijing Country: China Region: Asia Sales: 9000 Program finished, press Enter/Return to continue:
九. 投影:在查詢中創建新對象
1. 投影(projection)是在LINQ查詢中從其他數據類型中創建新數據類型的技術術語
2. 對于轉換查詢中的數字數據類型
select n + 1
3. 對于字符串數據類型查詢
select s.ToUpper()
4. 示例
A. 創建一個新的控制臺程序 ProjectionCreateNewObjects
B. copy上面例子中的customer代碼
C. copy上面例子中的main函數代碼
D. 修改上面例子中的main函數代碼
var queryResults = from c in customers where c.Region == "North America" select new { c.City, c.Country, c.Sales } ; foreach (var item in queryResults) { Console.WriteLine(item); }
E. 運行即可
{ City = New York, Country = USA, Sales = 9999 } { City = Mexico City, Country = Mexico, Sales = 2000 } { City = Los Angeles, Country = USA, Sales = 5000 } Program finished, press Enter/Return to continue:
十. 投影:方法語法
1. 投影查詢的方法語法版本是通過把LINQ方法Select()的調用關聯到我們調用的其他LINQ方法上來實現的
例如
如果Where()方法調用上添加Select()方法調用,就會得到相同的查詢結果:
var queryResults = customers.Where(c => c.Region == "North America") .Select(c => new { c.City, c.Country, c.Sales });
2. 在查詢語法中需要select子句
但在方法語法中不需要Select()方法,除非在進行投影(改變結果集中所查詢的原始類型)
3. 方法調用順序不固定,可以在Where()方法的結果上調用Select()方法,反之亦然
但是,根據查詢的特性,調用順序也許很重要
比如
var queryResults = customers.Where(c => c.Region == "North America") .Select(c => new { c.City, c.Country, c.Sales }); // 正確
var queryResults = customers.Select(c => new { c.City, c.Country, c.Sales }) .Where(c => c.Region == "North America"); // 錯誤,因為Region屬性未包含在Select()投影創建的匿名類型{c.City, c.Country, c.Sales }中
var queryResults = customers.Select(c => new {c.City, c.Country, c.Sales }) .Where(c => c.City == "New York"); // 正確
十一. 單值選擇查詢
1. SELECT DISTINCT查詢,該查詢可搜索數據中的唯一值,也就是說,值是不重復的
2. 示例
A. 在上面的示例中,修改main函數的代碼
var queryResults = customers.Select(c => c.Region).Distinct();
B. 運行即可
North America Asia South America Europe Africa Program finished, press Enter/Return to continue:
十二. Any 和 All
1. 常常需要確定數據是否滿足某個條件,或者確保所有數據都滿足某個條件
LINQ提供了兩個布爾方法:Any()和All(),它們可以快速確定對于數據而言,某個條件是true還是false。
2. 示例
A. 上面的示例中,修改main函數的代碼,在sustomers聲明后的代碼改為如下所示
bool anyUSA = customers.Any(c => c.Country == "USA"); // 調用了Any()方法,用一個簡單的Lambda表達式檢查Customer類的Country字段的值是否是USAif (anyUSA) { Console.WriteLine("Some customers are in the USA"); } else { Console.WriteLine("No customers are in the USA"); }
/* 檢查Any()方法返回的布爾結果變量,輸出一個消息,顯示查詢的結果
Any()方法雖然僅返回true或false,但它會執行一個查詢,得到true或false結果 */
bool allAsia = customers.All(c => c.Region == "Asia");
/* 調用了All()方法,利用另一個簡單的Lambda表達式確定是否所有的顧客都來自亞洲 */
if (allAsia) { Console.WriteLine("All customers are in Asia"); } else { Console.WriteLine("Not all customers are in Asia"); }
B. 運行即可
Some customers are in the USA Not all customers are in Asia Program finished, press Enter/Return to continue:
十三. 多級排序
1. 比如上例中,進一步要求,需要查詢管理,并按照區域使結果以字母順序排列,再按照區域使結果以國家或城市名稱來排序
2. 示例
A. 上例中,修改main函數代碼,在customers后修改
var queryResults = from c in customers orderby c.Region, c.Country descending, c.City // 按照區域升序排序,再按照國家降序排序select new { c.ID, c.Region, c.Country, c.City } ;
B. 運行即可
{ ID = O, Region = Africa, Country = Egypt, City = Cairo } { ID = J, Region = Africa, Country = Nigeria, City = Lagos } { ID = R, Region = Asia, Country = China, City = Beijing } { ID = I, Region = Asia, Country = China, City = Shanghai } { ID = D, Region = Asia, Country = India, City = Delhi } { ID = B, Region = Asia, Country = India, City = Mumbai } { ID = L, Region = Asia, Country = Indonesia, City = Jakarta } { ID = P, Region = Asia, Country = Iran, City = Tehran } { ID = M, Region = Asia, Country = Japan, City = Tokyo } { ID = G, Region = Asia, Country = Korea, City = Seoul } { ID = C, Region = Asia, Country = Pakistan, City = Karachi } { ID = H, Region = Asia, Country = Turkey, City = Istanbul } { ID = F, Region = Europe, Country = Russia, City = Moscow } { ID = Q, Region = Europe, Country = UK, City = London } { ID = K, Region = North America, Country = Mexico, City = Mexico City } { ID = N, Region = North America, Country = USA, City = Los Angeles } { ID = A, Region = North America, Country = USA, City = New York } { ID = E, Region = South America, Country = Brazil, City = S~ao Paulo } { ID = S, Region = South America, Country = Colombia, City = Bogot′a } { ID = T, Region = South America, Country = Peru, City = Lima } Program finished, press Enter/Return to continue:
十四. 多級排序方法語法:ThenBy
1. 使用方法語法進行多級排序,需要使用了ThenBy()和OrderBy()方法
例如
var queryResults = customers.OrderBy(c => c.Region) .ThenBy(c => c.Country) .ThenBy(c => c.City) .Select(c => new { c.ID, c.Region, c.Country, c.City });
2. 如果第一個字段是以降序排序,就應調用OrderByDescending()來指定降序排序;
如果其他字段要以降序排序,就應調用ThenByDescending()來指定
例如
var queryResults = customers.OrderBy(c => c.Region) .ThenByDescending(c => c.Country) .ThenBy(c => c.City) .Select(c => new { c.ID, c.Region, c.Country, c.City });
十五. 分組查詢(或稱為組合查詢)
1. 分組查詢(group query)把數據分解為組,允許按組來排序、計算聚合值以及進行比較
2. 示例,要按照國家或區域比較銷售量,確定在哪里開新店或雇傭更多的員工
A. 創建一個新的控制臺程序GroupQuery
B. 依然使用之前示例中的customers的代碼
C. 修改main函數的代碼
var queryResults = from c in customers group c by c.Region into cg /* 分組查詢中的數據通過一個Region 鍵字段來分組
要計算每個組的總和,應生成一個新的結果集cg */select new { TotalSales = cg.Sum(c => c.Sales), Region = cg.Key } ; var orderedResults = from cg in queryResults orderby cg.TotalSales descending // 按照TotalSales字段對結果降序排序select cg ;
D. 在main函數中添加如下代碼
Console.WriteLine("Total/t: By/nSales/t: Region/n-----/t ------"); foreach (var item in orderedResults) { Console.WriteLine(item.TotalSales + "/t: " + item.Region); }
E. 運行即可
Total : By Sales : Region ----- ------ 52997 : Asia 16999 : North America 12444 : Europe 8558 : South America 7000 : Africa
十六. Take和Skip
1. 假定需要數據集中銷售量位于前5名的顧客。我們事先并不知道躋身前5名需要達到多高的銷量,所以不能使用where條件查找他們。
一些SQL數據庫(如Microsoft SQL Server)實現了TOP運算符,所以可以執行命令SELECT TOP 5 FROM ...,獲得前5名顧客的數據
與這個操作對應的LINQ方法是Take(),它可以從查詢結果中提取前n個結果
這個方法需要和orderby子句一起使用,才能獲得前n個結果
但orderby子句并不是必需的,因為有時知道數據已經按指定的順序排列好了,或者只需要前n個結果,而不必考慮它們的順序
2. Take()的反面是Skip(),它可以跳過前n個結果,返回剩余的結果
Take()和Skip()在LINQ文檔說明中稱為分區運算符(partitioning Operators),因為它們把結果集分為前n個結果[Take()]和/或其余的結果[Skip()]。
3. 示例
A. 在上例中,修改main函數,在customers后,修改代碼
var queryResults = from c in customers orderby c.Sales descending select new { c.ID, c.City, c.Country, c.Sales } // 沒有where子句,因為我們要獲得所有的顧客(按銷售量從高到低排序);
B. 輸入兩個結果處理循環,一個使用Take(),另一個使用Skip()
Console.WriteLine("Top Five Customers by Sales") foreach (var item in queryResults.Take(5)) { Console.WriteLine(item); } Console.WriteLine("Customers Not In Top Five"); foreach (var item in queryResults.Skip(5)) // 跳過前5項(這些項剛才已經輸出了),從原來的查詢結果集中輸出剩余的顧客{ Console.WriteLine(item); }
C. 運行即可
Top Five Customers by Sales { ID = A, City = New York, Country = USA, Sales = 9999 } { ID = R, City = Beijing, Country = China, Sales = 9000 } { ID = B, City = Mumbai, Country = India, Sales = 8888 } { ID = Q, City = London, Country = UK, Sales = 8000 } { ID = C, City = Karachi, Country = Pakistan, Sales = 7777 } Customers Not In Top Five { ID = P, City = Tehran, Country = Iran, Sales = 7000 } { ID = D, City = Delhi, Country = India, Sales = 6666 } { ID = O, City = Cairo, Country = Egypt, Sales = 6000 } { ID = E, City = S~ao Paulo, Country = Brazil, Sales = 5555 } { ID = N, City = Los Angeles, Country = USA, Sales = 5000 } { ID = F, City = Moscow, Country = Russia, Sales = 4444 } { ID = M, City = Tokyo, Country = Japan, Sales = 4000 } { ID = G, City = Seoul, Country = Korea, Sales = 3333 } { ID = L, City = Jakarta, Country = Indonesia, Sales = 3000 } { ID = H, City = Istanbul, Country = Turkey, Sales = 2222 } { ID = T, City = Lima, Country = Peru, Sales = 2002 } { ID = K, City = Mexico City, Country = Mexico, Sales = 2000 } { ID = I, City = Shanghai, Country = China, Sales = 1111 }
{ ID = S, City = Bogot′a, Country = Colombia, Sales = 1001 } { ID = J, City = Lagos, Country = Nigeria, Sales = 1000 } Program finished, press Enter/Return to continue:
十七. First和FirstOrDefault
1. First()方法
假定需要在數據集中查找一名來自非洲的顧客,我們需要實際的數據,而不是true/false值或者包含所有匹配值的結果集。
First()方法提供了這個功能,它返回結果集中第一個匹配給定條件的元素。
2. FirstOrDefault()方法
如果沒有來自非洲的顧客,就用FirstOrDefault()來處理這種情況,而無需添加錯誤處理代碼
3. 示例
A. 在上例中,修改main函數,在customers后,修改代碼
var queryResults = from c in customers select new { c.City, c.Country, c.Region } /* 沒有where和orderby子句。我們用select語句投影了感興趣的字段。
本例中選擇了City、Country和Region屬性 */;
B. 使用First()和FirstOrDefault()方法輸入如下查詢
Console.WriteLine("A customer in Africa"); Console.WriteLine(queryResults.First(c => c.Region == "Africa")); // First()運算符返回一個對象值,而不是結果集,所以不需要創建foreach循環,直接輸出結果即可Console.WriteLine("A customer in Antarctica"); Console.WriteLine(queryResults.FirstOrDefault(c => c.Region == "Antarctica")); // 使用FirstOrDefault()查詢南極洲區域
C. 運行即可
A customer in Africa { City = Lagos, Country = Nigeria, Region = Africa } A customer in Antarctica
// 這行代碼找不到任何結果,所以返回空(空結果集),輸出空白Program finished, press Enter/Return to continue:
4. 如果給南極洲查詢使用First()運算符,而不是FirstOrDefault(),就會得到如下異常:System.InvalidOperationException: Sequence contains no matching element
使用FirstOrDefault()時,當查詢條件不滿足時,將為customers列表返回默認元素,
而使用First()時則是返回null(因為這些元素的類型未知)。
因而這里對南極洲地區查詢時,您會收到一條異常消息。
十八. 集運算符
1. 標準的集運算符(set operator),如Union()合Intersect(),對查詢結果執行操作
2. 示例
A. 上面的示例中,在Customer類后面添加Order類
class Order { public string ID { get; set; } public decimal Amount { get; set; } }
B. 在Main()方法的customers列表初始化之后,用如下數據創建并初始化一個orders列表
List<Order> orders = new List<Order> { new Order { ID="P", Amount=100 }, new Order { ID="Q", Amount=200 }, new Order { ID="R", Amount=300 }, new Order { ID="S", Amount=400 }, new Order { ID="T", Amount=500 }, new Order { ID="U", Amount=600 }, new Order { ID="V", Amount=700 }, new Order { ID="W", Amount=800 }, new Order { ID="X", Amount=900 }, new Order { ID="Y", Amount=1000 }, new Order { ID="Z", Amount=1100 } };
C. 在orders列表初始化后,輸入如下查詢
var customerIDs = from c in customers select c.ID ; var orderIDs = from o in orders select o.ID ;
// 使用兩個簡單的from...select查詢來獲取Customer類和Order類的ID字段
D. 用Intersect()輸入如下查詢
var customersWithOrders = customerIDs.Intersect(orderIDs);
// 使用Intersect()集運算符查找也在orderIDs結果中有訂單的顧客ID。只有在兩個結果集中都有的ID才包含在交集中Console.WriteLine("Customers with Orders:"); foreach (var item in customersWithOrders) { Console.Write("{0} ", item);
} Console.WriteLine();
/* 結果集的輸出利用了一個事實:ID是單個字符,所以使用Console.Write()調用,而本是WriteLine()調用,
直到foreach循環的最后才使用WriteLine(),使輸出緊湊、簡潔 */
E. 用Except()輸入如下查詢
Console.WriteLine("Orders with no customers:"); var ordersNoCustomers = orderIDs.Except(customerIDs);
// 使用Except()運算符查找沒有匹配顧客的訂單IDforeach (var item in ordersNoCustomers) { Console.Write("{0} ", item); } Console.WriteLine();
F. 用Union()輸入如下查詢
Console.WriteLine("All Customer and Order IDs:"); var allCustomerOrderIDs = orderIDs.Union(customerIDs);
// 使用Union()運算符查找所有顧客ID和訂單ID字段的并集foreach (var item in allCustomerOrderIDs) { Console.Write("{0} ", item); } Console.WriteLine();
// ID的輸出順序與它們在顧客和訂單列表中的順序相同,只是刪除了重復的項
G. 運行即可
Customers IDs with Orders: P Q R S T Order IDs with no customers: U V W X Y Z All Customer and Order IDs: P Q R S T U V W X Y Z A B C D E F G H I J K L M N O Program finished, press Enter/Return to continue:
3. 集運算符要求集成員有相同的類型,才能確保得到希望的結果。
這里利用了一個事實:兩個對象類型中的ID都是字符串,有相同的語義(類似于數據庫中的外鍵)。
集運算符非常有用,但它們的實際用處因為受到所有對象的類型都必須相同的限制而縮小了
十九. Join查詢
1. 用一個查詢搜索兩個列表中相關的數據,用鍵字段把結果連接起來
專門為處理不同對象類型而設計的Join語句
2. 示例
A. 上面的示例中,cusomer類,order類,customers列表,order訂單列表都不變
修改main函數代碼,在customers和orders列表初始化之后,輸入如下所示的查詢
var queryResults = from c in customers join o in orders on c.ID equals o.ID
/* 查詢使用join關鍵字通過Customer類和Order類的ID字段,把每個顧客與其對應的訂單連接起來
on關鍵字在關鍵字段ID的后面,equals關鍵字指定另一個集合中的對應字段。
查詢結果僅包含兩個集中ID字段值相同的對象數據 */select new { c.ID, c.City, SalesBefore = c.Sales, NeWorder = o.Amount, SalesAfter = c.Sales+o.Amount };
//select語句投影了一個帶指定屬性的新數據類型,因此可以清楚地看到最初的總銷售量、新訂單和最終的新總銷售量
B. 用前面例子中使用的標準foreach查詢處理循環結束程序
foreach (var item in queryResults) { Console.WriteLine(item); }
// 這個程序沒有在customer對象中遞增總銷售量,但您可以在自己的業務邏輯中完成這一任務
C. 運行即可
{ ID = P, City = Tehran, SalesBefore = 7000, NewOrder = 100, SalesAfter = 7100 } { ID = Q, City = London, SalesBefore = 8000, NewOrder = 200, SalesAfter = 8200 } { ID = R, City = Beijing, SalesBefore = 9000, NewOrder = 300, SalesAfter = 9300 } { ID = S, City = Bogot′a, SalesBefore = 1001, NewOrder = 400, SalesAfter = 1401 } { ID = T, City = Lima, SalesBefore = 2002, NewOrder = 500, SalesAfter = 2502 } Program finished, press Enter/Return to continue:
新聞熱點
疑難解答