当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > LINQ学习笔记:子查询和延迟执行

ASP.NET
不同映射模式下的直线输出的效果问题
ASP.NET开发下的MVC设计模式的实现
ASP.NET编写应用程序的十大技巧
ASP.NET中使用AJAX的简单方法
ASP.NET MVC实现自己的视图引擎
认识asp.net会话状态
ASP.NET实现页面传值的几种方法
.NET中容易混淆的几组重要概念
详解.NET中的动态编译技术
如何使用ASP.Net加密Cookie
ASP.NET 2.0跨网页提交的三种方法
ASP.NET 2.0创建母版页引来的麻烦
.Net整合其他平台的一些探讨
ASP.NET编程经验技巧10则
最佳实践 ADO.NET实用经验无保留曝光
在.NET上执行多线程操作要考虑的两大因素
.Net开发 细说Visual Basic.Net
ASP.NET网络编程中经常用到的27个函数集
ASP.NET防止用户多次登录的方法
对ASP.NET MVC项目中的视图做单元测试

ASP.NET 中的 LINQ学习笔记:子查询和延迟执行


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 62 ::
收藏到网摘: n/a

子查询

子查询是一个包含了另外一个查询的Lambda表达式的查询. 以下的例子使用了一个子查询来针对篮球明星的last name排序:

 1: string[] players = { "Tim Ducan", "Lebrom James", "Kobe Byrant" };
 2: IEnumerable<string> q = players.OrderBy (m => m.Split().Last());

在这其中, Last是一个子查询, q则代表了一个外部查询.

在子查询中, 你可以在Lambda表达式的右边使用任何可行的C#表达语法. 子查询只是一个简单的C#表达式, 这意味着所有适用于子查询的规则都可以推导到Lambda表达式上.

以下的查询取得一个字符数组中所有满足长度等于最小长度的字符序列:

 1: string[] names = { "James","Jack","Landy","C.Y","Jay" };
 2: IEnumerable<string> q = names
 3: .Where (n => n.Length ==
 4: names.OrderBy (n2 => n2.Length)
 5: .Select (n2 => n2.Length).First( )
 6: );
 7: foreach(var s in q)
 8: {
 9: Console.WriteLine(s); //C.Y , Jay
 10: }

对于子查询, 可以引用到外部的Lambda参数或者是迭代变量(在复合查询中). 例如上述的例子中, 如果OrderBy使用的表达式改为(n => n.Length)而不是用n2的话将会得到一个错误信息:

A local variable named ‘n’ cannot be declared in this scope because it would give a different meaning to ‘n’, which is already used in a ‘parent or current’ scope to denote something else.

针对这个例子, 我们可以看到对应的复合查询写法:

 1: IEnumerable<string> q =
 2: from n in names
 3: where n.Length ==
 4: (from n2 in names
 5: orderby n2.Length
 6: select n2.Length).First( )
 7: select n;

外部迭代变量n在子查询范围内是可见的, 因此我们不能将它重用为子查询内部的迭代变量.

子查询会在对应的Lambda表达式被执行的时候来执行, 其执行取决于外部查询, 也可以说是由外到里来处理的. 本地查询完全遵循这个模型, 但是解释型查询(例如LINQ to SQL)则仅仅是概念上遵循而已.

之前的查询我们还可以使用一种更加简洁的写法:

 1: IEnumerable<string> q =
 2: from n in names
 3: where n.Length ==
 4: names.OrderBy (n2 => n2.Length).First().Length
 5: select n;

如果使用Min聚合函数, 还可以进一步简化:

 1: IEnumerable<string> q =
 2: from n in names
 3: where n.Length == names.Min (n2 => n2.Length)
 4: select n;

实际上, 由于n2.Length在外部查询循环的时候每次都会重新计算, 这在某些情况下可能会引起效率问题, 避免这个问题, 我们可以将子查询分离出来:

 1: int len = names.Min (n => n.Length);
 2:  
 3: IEnumerable<string> query = from n in names
 4: where n.Length == len
 5: select n;

子查询和延迟执行

在子查询中的返回单一元素或者聚合类操作符, 例如first或者Count, 并不会强制外部查询立即执行, 也就说外部查询依然拥有延迟执行的能力. 这是因为子查询是被间接调用的 – 如果是本地查询则是通过代理(delegate), 如果是解释性查询则是通过表达树(expression tree).

一个有趣的现象是当你的子查询中包含一个Select表达式的时候, 如果是本地查询, 你实际上是将其发散成一序列的查询 – 并且每一个都拥有延迟执行的能力. 这个影响是透明的, 因为它可以显著提高效率. 待续!