LINQ 简介

来源:互联网 发布:2016淘宝女装销量前十 编辑:程序博客网 时间:2024/06/13 03:19

一. 第一个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 => 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(); 

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字段的值是否是USA
if (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()运算符查找没有匹配顾客的订单ID
foreach (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:










0 0
原创粉丝点击