在上一篇文章中说了几个常用的操作,本篇文章中将会说明下其他的查询操作符。
必备知识
C#3.0基础
基础数据(代码3.1)
- public static Modules[] ModuleList =
- {
- EmployeeManager,
- new Modules{
- Project = ProjectList[0],
- ParentModule = EmployeeManager,
- ModuleID="EmployeeBasicInfo",ModuleName="员工基础信息管理",IsHaveChild=true,CreateDate=DateTime.Now
- },
- new Modules{
- Project = ProjectList[1],
- ModuleID="EmployeeBasicInfo",ModuleName="员工基础信息管理",IsHaveChild=true,CreateDate=DateTime.Now
- },
- new Modules{
- Project = ProjectList[1],
- ModuleID="EmployeeBasicInfo",ModuleName="??基础信息管理",IsHaveChild=true,CreateDate=DateTime.Now
- },
- new Modules{
- Project = ProjectList[2],
- ModuleID="EmployeeBasicInfo",ModuleName="?册管理",IsHaveChild=true,CreateDate=DateTime.Now
- },
- new Modules{
- Project = ProjectList[2],
- ModuleID="EmployeeBasicInfo",ModuleName="作业单管理",IsHaveChild=true,CreateDate=DateTime.Now
- }
- };
查询操作
1)Group By
我们可以看到模块中有属于多个项目的,现在我们想根据项目进行分组下,看下代码(代码3.2):
- var modules = from module in BaseData.ModuleList
- group module by module.Project into projectModules
- select new
- {
- ProjectName = projectModules.Key.ProjectsName,
- ModuleList = projectModules
- };
- GridView1.DataSource = modules;
- GridView1.DataBind();
前台代码(代码3.3):
- <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
- <Columns>
- <asp:BoundField HeaderText="ProjectName" DataField="ProjectName" />
- <asp:TemplateField HeaderText="Modules">
- <ItemTemplate>
- <asp:BulletedList runat="server" ID="bulletedList1"
- DataSource='<%# Eval("ModuleList") %>' DataValueField="ModuleName">
- </asp:BulletedList>
- </ItemTemplate>
- </asp:TemplateField>
- </Columns>
- </asp:GridView>
运行结果:
扩展方法的方式也可以这么写(代码3.4):
- var modules = BaseData.ModuleList.GroupBy(module => module.Project)
- .Select(module => new { ProjectName = module.Key.ProjectsName, ModuleList=module});
在3.2的代码中我们可以看到,分组名叫projectModules,每个分组都是实现了IGrouping<TKey,T>的接口。我们来看看IGrouping<TKey,T>的定义(代码3.5):
- public interface IGrouping<TKey, T> : IEnumerable<T>
- {
- TKey Key { get; }
- }
在这可以看到Key是一个Tkey类型的,而Key就是代码3.2module.Project。
2)嵌套查询
其实上面的实现我们也可以通过嵌套查询来实现(代码3.6):
- var modules = from project in BaseData.ProjectList
- select new
- {
- ProjectName=project.ProjectsName,
- ModuleList=from module in BaseData.ModuleList
- where module.Project.ProjectsID == project.ProjectsID
- select module
- };
其结果是一样的,但是如果我们再Project里面加一条记录,而没有Module呢:
而用分组则得到:
其原因其实很简单,因为我们分组是去查的ModuleList而嵌套查询时相对于ProjectList进行的。
3)Join
Join就是连接查询,用过sql的朋友都知道连接分为好几种类型,下面一一来说下。
组连接
我们首先来看用连接再实现上面的要求(代码3.6):
- var modules = from project in BaseData.ProjectList
- join module in BaseData.ModuleList on
- project equals module.Project into projectModules
- select new
- {
- ProjectName = project.ProjectsName,
- ModuleList = projectModules
- };
其运行效果跟嵌套查询时一样的。
内连
内联的实现其实只是跟上面的组连接稍微有点变通(代码3.7):
- var modules = from project in BaseData.ProjectList
- join module in BaseData.ModuleList
- on project equals module.Project
- select new
- {
- ProjectName = project.ProjectsName,
- ModuleName = module.ModuleName
- };
可以看到如下结果:
左连
在上面的例子中我们看到了,只有有Module的Project才显示出来了,下面看下左联的代码(代码3.8):
- var modules = from project in BaseData.ProjectList
- join module in BaseData.ModuleList
- on project equals module.Project into ProjectModules
- from module in ProjectModules.DefaultIfEmpty()
- select new
- {
- ProjectName = project.ProjectsName,
- ModuleName = module==default(Modules)? "No Modules":module.ModuleName
- };
效果:
首先我们来看下组连跟内联的区别在于,投影时,我们组连使用的是projectModules而内连使用的是module,这个很好理解,主要说下左连如何实现的。首先看下DefaultIfEmpty方法的申明(代码3.9):
- public static IEnumerable<TSource> DefaultIfEmpty<TSource>(
- this IEnumerable<TSource> source
- )
DefaultIfEmpty方法的作用就是:返回指定序列的元素;如果序列为空,则返回单一实例集合中的类型参数的默认值。这里我们主要通过先组连然后再来同过DefaultIfEmpty方法实现了左连。
交叉连接
其实在上面的左查询中我们已经用过了交叉连接,示例代码(代码3.10):
- var modules = from project in BaseData.ProjectList
- from module in BaseData.ModuleList
- select new {
- ProjectName = project.ProjectsName,
- ModuleName = module.ModuleName
- };
结果就不列出来了。
总结
在这篇文章中我们详细说明GroupBy、嵌套查询、Join查询操作符,通过这篇和上篇文章我们基本上掌握了些基础的查询,在下篇文章中将会就实际开发中使用的技巧进行一个说明。