linq标准查询操作符
LINQ标准查询操作符 Linq是语言集成查询的简称。Linq简化了语言查询,是 的程序员可以使用相同的语法查询不同的数据源。 本文是闲暇之余学习Linq的产物。代码是花了大约一周 的业余时间组织的,敲出来只是为了记住它。本文使用的Linq 查询包含了两种方式,一种是直接查询,另一种是使用 System.Linq中定义的扩展方法进行的查询。对于扩展方法查 询的方式,使用了大量的Lambda表的是和系统定义的委托 Funco不熟悉这两个东西的童鞋们可以在本博找到相关的 、-、、广 又早: 【文章1】【文章2】 一、准备供查询的数据 本文首先构建一个提供数据的实体类供以后的查询使 用。本文使用的实体类包含了 1950到2008年一级方程式锦 标赛的冠军车队和冠军赛手。这些数据是使用了实体类和列 表来准备的。 首先定义代表赛手的实体类Racero Racer类定义了几个 属性和一个重载的ToString()方法,该方法以指定的格式显示 赛手。Racer类实现了 Iattable接口,以支持格式字符串 的不同变体。这个类还实现类IComparable接口,用以根 据赛手的LastName进行排序。为了执行高级查询Racer类同 时包含了单值属性如FirstName、LastName、Wins (获胜次 数)、Country (国籍)和Starts。同时也包含了多值属性如: Cars (赛手在获得冠军的年份所使用的赛车)和Years (赛手 获得冠军的年份,赛手可以多次获得冠军)。这个类具体的 实现如下: 【代码】 第二个实体类是Teamo这个类包含了车队冠军的名字 和获得冠军的年份。 【代码】 第三个类是ulal.这个类定义方法GetChampions方 法返回一组表示以及方程式赛车冠军的列表。 【代码】 这个类还定义了一个方法:GetConstructorChampions()o 用于返回所有车队冠军的列表。 【代码】 二、System.Linq中的扩展方法 扩展方法的作用是将方法写入最初没有定义该方法的 类中。还可以将方法添加到实现某个特定接口的任何类中, 这样多个类就可以使用相同的实现代码。对于扩展方法本文 不做详细介绍,只是扩展方法在Linq查询中使用较多需要预 先了解。尤其是System.Core程序集下定义的System.Linq方 法。本文后边将会用到。 三、使用Linq进行查询 有了这些预备知识和实体类,我们就可以使用Linq进行 查询了。 1、简单的筛选 使用Where子句可以对数据源进行简单的筛选。下变例 子是找出至少赢得15场比赛的奥地利车手: 【代码1] 这段代码的功能可以使用System.Linq中的扩展方法来 实现: 【代码】 注:并不是所有的查询都可以使用Linq查询或者扩展方 法都可以实现的。高级查询需要使用扩展方法。 2、用索引进行筛选 Where()扩展方法的一个重载中,可以对该方法传递第二 个参数:索引。索引是筛选器返回的每个结果的计数器,可 以在表达式中使用索引,执行一些索引相关的计算。现编的 代码使用Where()扩展方法,返回姓氏以A开头,索引为偶 数的车手: 【代码】 3、筛选出不同的数据类型 使用OfType()扩展方法,可以实现基于类型的筛选。下 面的代码中定义了包含了 string和int类型的对象,使用 OfTypeO方法从集合中找出字符串: 【代码】 4、复合的from子句 复合的from子句用于对这样一种情况的查询:需要根 据对象的一个成员进行筛选,而这个成员本身是一组数据。 本例中,Racer类定义的属性Cars就是这样的一个属性。 Cars是一个字符串数组。 使用如下的Linq查询可以筛选出嘉实法拉利的所有冠 军: 【代码】 其中,第一个from子句用于访问从 ylal.GetChampions 方法返回的 Racer 对象,第二个 from 子句访问Racer类的Cars属性,返回所有string类型的赛车, 最后使用Where子句从这些赛车中筛选出所有冠军。 这里C#编译器将符合的from子句和Linq查询转换成 SelectMany()方法,SelectManyO方法可以用于迭代序列的序 列。使用SelectManyO扩展方法的代码如下: 【代码】 这里SelectManyO方法的第一个参数是隐式参数,他从 GetChampions方法中接收Racer对象序列,第二个参数是 collectionselector委托,其中定义了内部序列。在Lambda表 达式r=>r.Cars中,返回赛车集合。第三个参数是一个Func 委托,这里为每个Car调用该委托接收Racer和Cars对象。 Lambda表达式创建了一个包含了 Racer和Cars属性的匿名 的类型。这个SelectMany方法的结果摊平了赛手和赛车的层 次结构,为每个赛车返回匿名类型的一个新对象耦合。 这段解释有点拗口,因为Lambda表达式确实比较难以 解释,还有使用了几个Func委托,不了解委托看这段代 码简直就是天书。不过VS的职能提示挺管用的,在敲出几 个代码之后看看他的提示在继续写也是不错的。 5、对筛选结果进行排序 使用 ord er by 和 orderby descending 子句或者 OrderByO 和OrderByDescending()扩展方法可以实现对筛选结果的排序。 下面这段代码是对筛选出来的赛手使用赢得比赛的次 数进行排序: 【代码】 转换成扩展方法后的实现: 【代码】 6、对筛选结果进行分组 使用group子句和GroupByf)扩展方法可以对查询结果进 行分组。下边的例子是将赛车冠军按照国家进行分组,并列 出一个国家赛车冠军的总数: 【代码】 子句 group r by r.Country into g 根据 Country 属性组合所 有赛车手到一个新的标识符g中。g用于以后访问分组的结 果信息。group子句的结果根据扩展方法Count()的结果进行 排序o Select子句创建了一个带Country和Count属性的匿名 类型。这里有一个对象需要注意:g.Key。这指的是是group 方法筛选的依据,本例中g.Key就是分组依据Countryo 直接使用扩展方法中的GroupBy()和ThenByO方法也可 以实现相应的筛选功能: 【代码】 这里可以看出子句group r by r. Co untry into g被解析为 GroupBy(r=>r.Country),返回分组序列,之后进行了排序和筛 选等见大的操作即得到了需要的结果。 7、对嵌套对象进行分组 如果分组的对象应包含嵌套的序列,就可以改变select 子句创建的匿名类型。先看下面的代码: 【代码】 在上面的例子中,返回的国家不仅包含国家名和赛手数 量这两个属性,还包括赛手姓名序列。这个序列用一个赋予 Racers属性的from/in内部子句指定,内部的from子句使用 分组标识符g获取该分组中