一、什么是Linq
Linq是语言集成查询(Language Integrated Query)的简称,是visual Studio 2008和.NET Framework 3.5版本中一项突破性的创新,它在对象领域和数据领域之间架起了一座桥梁。
Linq支持各种数据源:
1、ADO.NET DataSet
2、XML文档
3、SQL Server数据库
4、支持IEnumerable或泛型IEnumerable(T)接口的任意对象集合
5、更多。。。
二、Linq的优点
1 select FirstName,LastName, * from Customers
2 where city = ' Shanghai '
3 order by district
简单的字符串表示,没有编译时类型检查,没有IDE的智能感知支持。
以上例子只是针对SQL,针对不同的数据源,例如XML文档、各种WEB服务等我们还要学习不同的查询方法。
完全类型检查和IDE智能感知支持。
三、Linq查询的步骤
所有的Linq查询操作都由以下三个不同的操作组成:
数据源
查询
查询执行
执行聚合函数(Count、Max、Average、First)。
调用ToList(<T>Source)或ToArray(<T>Source)方法缓存结果。
四、查询基本操作
1、from子句
用于获取数据源
1 var queryAllCustomers =
2 from cust in Customers
3 select cust;
2、复合from子句
在某些情况下,原序列中的每个元素本身可能是序列,也可能包含序列。用于访问某个数据源中的内部集合。
1 // 数据源
2 IList < Student > students = new List < Student >
3 {
4 new Student{ Name = " Kevin " , Score = new List < int > { 89 , 93 , 88 , 78 }},
5 new Student{ Name = " Jackie " ,Score = new List < int > { 92 , 87 , 83 , 91 }},
6 new Student{ Name = " Helen " ,Score = new List < int > { 53 , 76 , 72 , 62 }}
7 };
8
9 // 使用复合from子句查询命令
10 var getStudent =
11 from student in students
12 from score in student.Score
13 where score > 90
14 select new { Name = student.Name,Score = score};
需求:查询出成绩有90分以上的学生,得到他们的名字和成绩
分析:从代码中,我们可以看到学生对象中有个Score属性,Score属性本身就是List集合,这时候我们就要用到复合from子句进行查询了。首先遍历学生对象集合中的每个学生对象,然后在用另一个from子句,对每个学生对象中的Score属性进行遍历,筛选出含有90分以上的学生信息进行返回。
3、使用let子句扩展范围变量
用于创建查询自身的范围变量
1 string [] strings = {
2 " I am a new Student. " ,
3 " You are a talent "
4 };
5
6 var query = from sentences in strings
7 let words = sentences.Split( ' ' )
8 from word in words
9 let w = word.ToLower()
10 where w[ 0 ] == ' a ' || w[ 0 ] == ' e ' || w[ 0 ] == ' i ' || w[ 0 ] == ' o ' ||
w[ 0 ] == ' u '
11 select word;
12
13 foreach (var word in query)
14 {
15 Console.Write(word + " , " );
16 }
需求:将字符串数组中的两句英文语句中所有的元音字母打头的单词输出到控制台
分析:首先遍历字符串数组中的每个字符串,用let子句创建查询自身的范围变量words,并调用Split(' ')方法,将每个字符串中以空格分割为单词存入words变量中,然后再次使用let子句创建查询自身的范围变量word,并调用ToLower()方法,将每个单词都变为小写,最后筛选出首字母为元音的单词进行返回。
4、where子句
将一个布尔条件("谓词")应用于每个源元素(由范围变量引用),并返回满足指定条件的元素。
1 // 数据源
2 int [] arr = { 0 , 3 , 2 , 1 , 9 , 6 , 8 , 7 , 4 , 5 };
3
4 // 使用Where子句查询的查询语句
5 var query = from a in arr
6 where a < 5 && a % 2 == 0
7 select a;
8
9 // 执行查询
10 foreach (var a in query)
11 {
12 Console.WriteLine(a);
13 }
需求:将数组中小于5的偶数查询出来输出到控制台
分析:首先遍历数组中的每个元素,然后用where语句筛选出小于5,并且对2去模是0的数查询出来返回。
where子句不仅能使用表达式来进行筛选,还可以使用方法进行筛选。
1 public static bool IsEven( int a)
2 {
3 return a % 2 == 0 ? true : false ;
4 }
1 // 数据源
2 int [] arr = { 0 , 3 , 2 , 1 , 9 , 6 , 8 , 7 , 4 , 5 };
3
4 // where子句也可以接受一个方法
5 var query = from a in arr
6 where IsEven(a)
7 select a;
8
9 foreach (var a in query)
10 {
11 Console.Write(a + " , " );
12 }
这就是一个在where语句中使用方法进行筛选的例子,输出的结果和上例完全一样。
使用where子句还要注意以下几点
5、orderby子句
1 var query = from a in arr
2 where IsEven(a)
3 orderby a ascending
4 select a;
接着上个例子的演示,本例是一个升序的排序。
1 var query = from a in arr
2 where IsEven(a)
3 orderby a descending
4 select a;
本例是一个降序的排序。
6、group子句
1 // 数据源
2 string [] fruits = { " apple " , " banana " , " peach " , " orange " , " melon " , " lemon " };
3
4 // 分组查询的查询语句
5 var query = from f in fruits
6 group f by f[ 0 ];
7
8 // 执行查询
9 foreach (var letters in query)
10 {
11 Console.WriteLine( " words that start with letter: " + letters.Key);
12 foreach (var word in letters)
13 {
14 Console.WriteLine(word);
15 }
16 }
需求:根据首字母分组,并打印到控制台
分析:首先遍历字符串数组中的每个字符串,然后根据每个字符串的首字母进行分组,返回结果
1 var query = from f in fruits
2 group f by f[ 0 ] into g
3 where g.Key == ' p ' || g.Key == ' b '
4 select g;
如果您想要对每个组执行附加查询操作,则可以使用into上下文关键字指定一个临时标识符。使用into时,必须继续编写该查询,并最终用一个select语句或另一个group子句结束该查询。
7、join子句
1)内部连接
1 var innerJoinQuery =
2 from category in categories
3 join prod in products on category.ID equals prod.CategoryID
4 select new { ProductName = prod.Name, Category = category.Name };
2)分组连接
1 var innerGroupJoinQuery =
2 from category in categories
3 join prod in products on category.ID equals prod.CategoryID
4 into prodGroup
5 select new { CategoryName = category.Name, Products = prodGroup };
3)左外部连接
1 var leftOuterJoinQuery =
2 from category in categories
3 join prod in products on category.ID equals prod.CategoryID
4 into prodGroup
5 from item in prodGroup.DefaultIfEmpty( new Product{Name =
6 string.Empty, CategoryID = 0 })
7 select new { CatName = category.Name, ProdName = item.Name };
在左外连接中,将返回左侧源序列中的所有元素,即使它们在右侧序列中没有匹配的元素也是如此。
若要在Linq中执行左外连接,请将DefaultIfEmpty方法与分组连接结合起来,以指定要在某个元素不具有匹配元素时产生的默认右侧元素,可以使用null作为任何引用类型的默认值。也可以指定用户定义的默认类型。
8、equals关键字
9、select子句(选择、投影)
select子句可以指定将在执行查询时产生的值的类型。该子句的结果将基于前面所有子句的计算结果以及select子句本身中的所有表达式。
查询表达式必须以select子句或group子句结束
在最简单的情况下,select子句仅指定范围变量。这会使返回的序列包含于数据源具有相同类型的元素。