代码改变世界

Linq学习笔记(三)Linq To Object查询操作符

2009-11-17 14:53  Henry Cui  阅读(1013)  评论(1编辑  收藏  举报

在上一篇文章中说了几个常用的操作,本篇文章中将会说明下其他的查询操作符。

必备知识

C#3.0基础

基础数据(代码3.1)

  1. public static Modules[] ModuleList =
  2. {
  3.     EmployeeManager,
  4.     new Modules{
  5.         Project  = ProjectList[0],
  6.         ParentModule = EmployeeManager,
  7.         ModuleID="EmployeeBasicInfo",ModuleName="员工基础信息管理",IsHaveChild=true,CreateDate=DateTime.Now
  8.     },
  9.     new Modules{
  10.         Project  = ProjectList[1],
  11.         ModuleID="EmployeeBasicInfo",ModuleName="员工基础信息管理",IsHaveChild=true,CreateDate=DateTime.Now
  12.     },
  13.     new Modules{
  14.         Project  = ProjectList[1],
  15.         ModuleID="EmployeeBasicInfo",ModuleName="??基础信息管理",IsHaveChild=true,CreateDate=DateTime.Now
  16.     },
  17.     new Modules{
  18.         Project  = ProjectList[2],
  19.         ModuleID="EmployeeBasicInfo",ModuleName="?册管理",IsHaveChild=true,CreateDate=DateTime.Now
  20.     },
  21.     new Modules{
  22.         Project  = ProjectList[2],
  23.         ModuleID="EmployeeBasicInfo",ModuleName="作业单管理",IsHaveChild=true,CreateDate=DateTime.Now
  24.     }
  25. };

 

查询操作

1)Group By

我们可以看到模块中有属于多个项目的,现在我们想根据项目进行分组下,看下代码(代码3.2):

  1. var modules = from module in BaseData.ModuleList
  2.               group module by module.Project into projectModules
  3.               select new
  4.               {
  5.                   ProjectName = projectModules.Key.ProjectsName,
  6.                   ModuleList = projectModules
  7.               };
  8. GridView1.DataSource = modules;
  9. GridView1.DataBind();

 

前台代码(代码3.3):

  1. <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
  2.           <Columns>
  3.               <asp:BoundField HeaderText="ProjectName" DataField="ProjectName" />
  4.               <asp:TemplateField HeaderText="Modules">
  5.                   <ItemTemplate>
  6.                       <asp:BulletedList runat="server" ID="bulletedList1"
  7.                           DataSource='<%# Eval("ModuleList") %>' DataValueField="ModuleName">
  8.                       </asp:BulletedList>
  9.                   </ItemTemplate>
  10.               </asp:TemplateField>
  11.           </Columns>
  12.       </asp:GridView>

运行结果:

image

扩展方法的方式也可以这么写(代码3.4):

  1. var modules = BaseData.ModuleList.GroupBy(module => module.Project)
  2.                 .Select(module => new { ProjectName = module.Key.ProjectsName, ModuleList=module});

 

在3.2的代码中我们可以看到,分组名叫projectModules,每个分组都是实现了IGrouping<TKey,T>的接口。我们来看看IGrouping<TKey,T>的定义(代码3.5):

  1. public interface IGrouping<TKey, T> : IEnumerable<T>
  2. {
  3.     TKey Key { get; }
  4. }

在这可以看到Key是一个Tkey类型的,而Key就是代码3.2module.Project。

2)嵌套查询

其实上面的实现我们也可以通过嵌套查询来实现(代码3.6):

  1. var modules = from project in BaseData.ProjectList
  2.                           select new
  3.                           {
  4.                               ProjectName=project.ProjectsName,
  5.                               ModuleList=from module in BaseData.ModuleList
  6.                                          where module.Project.ProjectsID == project.ProjectsID
  7.                                          select module
  8.                           };

其结果是一样的,但是如果我们再Project里面加一条记录,而没有Module呢:

image

而用分组则得到:

image

其原因其实很简单,因为我们分组是去查的ModuleList而嵌套查询时相对于ProjectList进行的。

 

3)Join

Join就是连接查询,用过sql的朋友都知道连接分为好几种类型,下面一一来说下。

组连接

我们首先来看用连接再实现上面的要求(代码3.6):

  1. var modules = from project in BaseData.ProjectList
  2.               join module in BaseData.ModuleList on
  3.                project equals module.Project into projectModules
  4.               select new
  5.               {
  6.                   ProjectName = project.ProjectsName,
  7.                   ModuleList = projectModules
  8.               };

其运行效果跟嵌套查询时一样的。

内连

内联的实现其实只是跟上面的组连接稍微有点变通(代码3.7):

  1. var modules = from project in BaseData.ProjectList
  2.               join module in BaseData.ModuleList
  3.               on project equals module.Project
  4.               select new
  5.               {
  6.                   ProjectName = project.ProjectsName,
  7.                   ModuleName = module.ModuleName
  8.               };

可以看到如下结果:

image

左连

在上面的例子中我们看到了,只有有Module的Project才显示出来了,下面看下左联的代码(代码3.8):

  1. var modules = from project in BaseData.ProjectList
  2.               join module in BaseData.ModuleList
  3.               on project equals module.Project into ProjectModules
  4.               from module in ProjectModules.DefaultIfEmpty()
  5.               select new
  6.               {
  7.                   ProjectName = project.ProjectsName,
  8.                   ModuleName = module==default(Modules)? "No Modules":module.ModuleName
  9.               };

效果:

image

首先我们来看下组连跟内联的区别在于,投影时,我们组连使用的是projectModules而内连使用的是module,这个很好理解,主要说下左连如何实现的。首先看下DefaultIfEmpty方法的申明(代码3.9):

  1. public static IEnumerable<TSource> DefaultIfEmpty<TSource>(
  2.     this IEnumerable<TSource> source
  3. )

DefaultIfEmpty方法的作用就是:返回指定序列的元素;如果序列为空,则返回单一实例集合中的类型参数的默认值。这里我们主要通过先组连然后再来同过DefaultIfEmpty方法实现了左连。

交叉连接

其实在上面的左查询中我们已经用过了交叉连接,示例代码(代码3.10):

  1. var modules = from project in BaseData.ProjectList
  2.               from module in BaseData.ModuleList
  3.               select new {
  4.                   ProjectName = project.ProjectsName,
  5.                   ModuleName = module.ModuleName
  6.               };

结果就不列出来了。

总结

在这篇文章中我们详细说明GroupBy、嵌套查询、Join查询操作符,通过这篇和上篇文章我们基本上掌握了些基础的查询,在下篇文章中将会就实际开发中使用的技巧进行一个说明。