linq标准查询操作符
LINQ标准查询操作符 Linq是语言集成查询的简称。Linq简化了语言查询,是 的程序员可以使用相同的语法查询不同的数据源。 本文是闲暇之余学习Linq的产物。代码是花了大约一周 的业余时间组织的,敲出来只是为了记住它。本文使用的Linq 查询包含了两种方式,一种是直接查询,另一种是使用 System.Linq中定义的扩展方法进行的查询。对于扩展方法查 询的方式,使用了大量的Lambda表的是和系统定义的委托 FuncTo不熟悉这两个东西的童鞋们可以在本博找到相关的 、-、、广 又早 【文章1】【文章2】 一、准备供查询的数据 本文首先构建一个提供数据的实体类供以后的查询使 用。本文使用的实体类包含了 1950到2008年一级方程式锦 标赛的冠军车队和冠军赛手。这些数据是使用了实体类和列 表来准备的。 首先定义代表赛手的实体类Racero Racer类定义了几个 属性和一个重载的ToString方法,该方法以指定的格式显示 赛手。Racer类实现了 Iattable接口,以支持格式字符串 的不同变体。这个类还实现类IComparableT接口,用以根 据赛手的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表 达式rr.Cars中,返回赛车集合。第三个参数是一个FuncT 委托,这里为每个Car调用该委托接收Racer和Cars对象。 Lambda表达式创建了一个包含了 Racer和Cars属性的匿名 的类型。这个SelectMany方法的结果摊平了赛手和赛车的层 次结构,为每个赛车返回匿名类型的一个新对象耦合。 这段解释有点拗口,因为Lambda表达式确实比较难以 解释,还有使用了几个FuncT委托,不了解委托看这段代 码简直就是天书。不过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被解析为 GroupByrr.Country,返回分组序列,之后进行了排序和筛 选等见大的操作即得到了需要的结果。 7、对嵌套对象进行分组 如果分组的对象应包含嵌套的序列,就可以改变select 子句创建的匿名类型。先看下面的代码 【代码】 在上面的例子中,返回的国家不仅包含国家名和赛手数 量这两个属性,还包括赛手姓名序列。这个序列用一个赋予 Racers属性的from/in内部子句指定,内部的from子句使用 分组标识符g获取该分组中