当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > LINQ学习笔记:创建更加复杂查询的策略

ASP.NET
使用函数传递参数来执行相应的数据库操作
如何实现在窗体和窗体之间进行传递数据
ASP.NET中文显示之两种解决方法
ASP.NET、JSP及PHP之间的抉择
ASP.NET 2.0发送电子邮件中存在的问题
谈谈HtmlControl与WebControl的区别与用途
从ASP.NET 1.1升级到ASP.NET 2.0要考虑的Cookie问题
通过系统配置来提高ASP.NET应用程序的稳定性
妙用ASP2.0中的URL映射改变网址
AJAX实现web页面中级联菜单的设计
ASP.NET跨页面传值技巧总结
再议ASP.NET DataGrid控件中的“添加新行”功能
Geometry 对象浅析
重构CollapsibleSplitter
如何利用.NET Framework使用RSS feed
ASP.NET获取IP与MAC地址的方法
在ASP.NET 2.0中使用样式、主题和皮肤
ASP.NET中为GridView添加删除提示框
ASP.NET 2.0,无刷新页面新境界
看看一个.net版对话框控件

ASP.NET 中的 LINQ学习笔记:创建更加复杂查询的策略


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

有3种策略可以应用于创建更加复杂的查询:

逐步创建 /使用into关键字/包装多个查询

逐步创建

之前我们曾演示过如何逐步的创建一个Lambda查询

 1: string[] players = { "Tim Ducan", "Lebrom James", "Kobe Byrant" };
 2: var filtered = players.Where (n => n.Contains ("a"));
 3: var sorted = filtered.OrderBy (n => n);
 4: var query = sorted.Select (n => n.ToUpper());

因为每一个参与的查询操作符都返回一个装饰序列, 其结果和你使用的单一的链式或多层装饰器的查询结果是一致的. 这里有几个潜在的好处, 如果你逐步的创建查询的话:

1. 查询更加简单容易编写

2. 可以有条件的添加查询操作符

在复合查询中使用逐步构造通常是很有用的做法. 为了演示, 假设我们想要使用正则表达式将所有的元音从一系列的名字中移除, 然后按字母排序并列出那些长度仍然大于2的名字. 使用Lambda语法, 我们可以使用一个单一的表达式完成:

 1: string[] names = { "James","Jack","Landy","C.Y","Jay" };
 2: IEnumerable<string> query = names
 3: .Select (n => Regex.Replace (n, "[aeiou]", ""))
 4: .Where (n => n.Length > 2)
 5: .OrderBy (n => n);
 6:  
 7: foreach(var name in query)
 8: {
 9: Console.WriteLine(name); //C.Y,Jck,Jms,Lndy
 10: }

如果我们将它直接翻译成复合查询语法的话会碰到一些问题, 因为复合查询语句必须按照where-orderby-select的顺序出现编译器才能正确编译. 但是如果我们简单的按这个要求重新排列的话, 结果将会不一样:

 1: string[] names = { "James","Jack","Landy","C.Y","Jay" }; IEnumerable<string> query =
 2: from n in names
 3: where n.Length > 2
 4: orderby n
 5: select Regex.Replace (n, "[aeiou]", "");
 6:  
 7: foreach(var name in query)
 8: {
 9: Console.WriteLine(name); //C.Y,Jck,Jms,Jy,Lndy 
 10: }

幸运的是使用复合查询语法我们还可以有很多的方法可以得到跟上述查询一致的结果. 这其中的第一种就是使用逐步构造查询:

 1: IEnumerable<string> query =
 2: from n in names
 3: select Regex.Replace (n, "[aeiou]", "");
 4:  
 5: query = from n in query
 6: where n.Length > 2
 7: orderby n
 8: select n;
 9:  
 10: foreach(var name in query)
 11: {
 12: Console.WriteLine(name); //C.Y,Jck,Jms,Lndy
 13: }

into关键字

into关键字可以让查询在经过一系列处理之后继续进行, 并且是逐步构造查询的快捷方式.使用into, 我们可以将上述的查询改写为:

 1: IEnumerable<string> query =
 2: from n in names
 3: select Regex.Replace (n, "[aeiou]", "")
 4: into noVowel
 5: where noVowel.Length > 2
 6: orderby noVowel
 7: select noVowel;

唯一可以使用into的地方是在select或者group语句之后. Into”重新开始”一个新的查询, 并且允许你继续使用全新的where, orderby 和select语句.

作用域规则

所有的查询变量在into关键字之后都不再属于自己的作用范围, 例如下面的查询将不会被编译通过:

 1: var query =
 2: from n1 in names
 3: select n1.ToUpper()
 4: into n2
 5: where n1.Contains ("x") // 非法, n1超出了作用域
 6: select n2;

要了解为什么, 考虑一下将上述查询转换成Lamdba语法之后:

 1: var query = names
 2: .Select (n1 => n1.ToUpper())
 3: .Where (n2 => n1.Contains ("x"));

当where运行的时候原始的名字(n1)已经丢失了, where操作符的输入序列只包含了大写的名字, 因此不能根据n1来过滤了.

包装查询

一个渐进查询可以被改造成一个包装查询, 如下例:

var tempQuery = tempQueryExpr

var finalQuery = from … in tempQuery…

也可以进一步改造为:

var finalQuery = from … in (tempQueryExpr)

包装查询从语义上等同于渐进式查询或者使用into关键字(没有中间变量). 最终结果就是只有一行包含多个操作符的查询语句. 例如, 考虑下面的查询:

 1: IEnumerable<string> query =
 2: from n in names
 3: select Regex.Replace (n, "[aeiou]", "");
 4:  
 5: query = from n in query
 6: where n.Length < 2
 7: orderby n
 8: select n;

包装改造以后:

 1: IEnumerable<string> query =
 2: from n1 in
 3: (
 4: from n2 in names
 5: select Regex.Replace (n2, "[aeiou]", "")
 6: )
 7: where n1.Length > 2 orderby n1 select n1;

当我们将它装成Lambda语法, 结果也是只有一行包含多个查询操作符的语句:

 1: IEnumerable<string> query = names
 2: .Select (n => Regex.Replace (n,"[aeiou]", ""))
 3: .Where (n => n.Length > 2)
 4: .OrderBy (n => n);

(编译器实际上不会执行最后的.Select(n=>n),因为它是多余的)

包装查询有时候可能会和我们之前谈过的子查询有点混淆, 因为它们之间很相似: 都有相似的inner和outer查询. 然而转换成Lambda语法的时候, 你会发现包装查询就是简单对于顺序链式操作符的包装(转换成Lambda之后操作符顺序跟包装查询的顺序完全一样). 而子查询并不是这样的, 它使用Lambda表达式将一个inner查询嵌入到另外一个当中. 待续!