C#学习笔记(八)—–LINQ查询之子查询

子查询

在linq中,所谓的子查询就是包含在另一个查询的Lambda表达式中的查询语句。下面这个示例中就是使用子查询对一组音乐家名字按姓氏排序:

string[] musos =
{ "David Gilmour", "Roger Waters", "Rick Wright", "Nick Mason" };
IEnumerable<string> query = musos.OrderBy (m => m.Split().Last());

m.Split将musos中的每个名字转换成一个字符型的数组,然后使用last运算符取出数组的最后一个元素,这里m.Split.Last就是一个子查询,这个子查询的结果可以供外部查询使用。
一个子查询实际上就是一个独立的C#表达式,可以是LINQ表达式,也可以是普通的逻辑判断,所以,只要是否和C#语法规则的内容,都可以放在Lambda表达式的右侧作为子查询来使用。也就是说,子查询的使用规则是有Lambda表达式的规则来决定的。提示:“子查询“这个词在通常的意义下,概念非常宽泛,我们只关注LINQ下的子查询,在运算符流语法中,子查询是指包含在Lambda表达式中的查询语句。在查询表达式的语法中,只要包含在其他查询语句中的查询,都是子查询,但是from字句除外。
子查询一般有两个作用:一个是为父查询确定查询范围,一般是一个较小的查询范围,另一个作用是为外层查询的Lambda表达式提供参数.
下面这个例子复杂点,它使用子查询取出一个字符串数组中长度最短的元素:

string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> outerQuery = names
.Where (n => n.Length == names.OrderBy (n2 => n2.Length)
.Select (n2 => n2.Length).First());
Tom, Jay

使用查询表达式语法可以实现同样的功能:

IEnumerable<string> outerQuery =
from n in names
where n.Length ==
(from n2 in names orderby n2.Length select n2.Length).First()
select n;

在上面的表达式中,范围变量n已经作为父查询的变量使用,所以在子查询左手凝固就不能在使用n作为范围变量了,这里使用了n2.
子查询在什么时候执行完全是由外部查询决定的,当外部查询就开始执行时,子查询也同时执行,他们是同步的,在整个查询中,子查询的执行结果被作为父查询的某个组成部分,我们可以认为查询的开始命令是从外向内传递的,对本地集合的查询严格按照这种由外向内的顺序进行;但对于数据库的查询,则没那么严格,只是原则是按照这种方式进行。
另一种理解方式是,子查询会在需要返回查询结果时执行,那什么时候需要子查询返回查询结果决定了外部查询什么时候被执行,在上面的例子中,子查询(那个传动带)会在每次外部循环中都执行,也就是这里的子查询是由外部循环触发的。结合下面这两张图,我们可以把之前用到的子查询简洁的定义为:

IEnumerable<string> query =
from n in names
where n.Length == names.OrderBy (n2 => n2.Length).First().Length
select n;

如果在上面这段代码中使用Min函数后,将会更进一步简洁化:

IEnumerable<string> query =
from n in names
where n.Length == names.Min (n2 => n2.Length)
select n;

这里写图片描述
这里写图片描述
在下面的章节中,会介绍如何使用lINQ查询远端数据源,如对SQL数据表的查询,上面的代码段是一个非常标准的查询语句,使用一个lINQ语句就完成了所有的操作,党对数据库进行查询时,只需访问一次数据库就可以全部完成。但对于本地数据源来说,上面这个查询语句在运行时效率比较低,因为字符串长度会被重复计算多次,我们可以单独运行子查询来避免这种重复的操作(单独运行的子查询实际上不是一个子查询,而是一个全新的查询语句)代码如下:

int shortest = names.Min (n => n.Length);
IEnumerable<string> query = from n in names
where n.Length == shortest
select n;

提示:在执行本地查询时,单独书写子查询是一种常用的方式,但是当子查询中的数据和外部查询有紧密关联的时候,即内部数据需要用到外部数据的值时,这种方式不合适,最好写成一个表达式,这种查询会在后面的章节进行描述。

子查询和延迟加载

子查询中使用单个元素或者聚合函数(count、first)的时候,整个LINQ查询语句并不会被强制执行,外部查询还是以延迟加载的方式执行。这是因为子查询是被间接执行的,在本地集合查询中,它通过委托的驱动来执行;而在远程数据源的查询中,它通过表达式树的方式执行。

如果select语句总包含了子查询,这这种情况下如果是本地查询,那么相当于将原序列重新封装到一个新的蓄力中,集合中的每个元素都是以延迟加载的方式执行的。关于这方面的介绍,将在后面做详细的介绍。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值