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

ASP.NET
asp.net GridView控件中模板列CheckBox全选、反选、取消
asp.net GridView 删除时弹出确认对话框(包括内容提示)
asp.net DropDownList 三级联动下拉菜单实现代码
asp DataTable添加列和行的三种方法
Asp.net 页面调用javascript变量的值
asp.net 长文章通过设定的行数分页
asp.net 定时间点执行任务的简易解决办法
asp.net 页面延时五秒,跳转到另外的页面
asp.net 动态输出透明gif图片
asp.net DataList与Repeater用法区别
asp.net Javascript获取CheckBoxList的value
asp.net程序在调式和发布之间图片路径问题的解决方法
asp.net下生成英文字符数字验证码的代码
asp.net 页面版文本框智能提示JSCode (升级版)
ASP.NET URL伪静态重写实现方法
ASP.NET 2.0 中Forms安全认证
asp.net 动态添加多个用户控件
asp.net Repeater显示父子表数据,无闪烁
asp.net 无法获取的内部内容,因为该内容不是文本 的解决方法
asp.net GridView排序简单实现

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 251 ::
收藏到网摘: 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查询嵌入到另外一个当中. 待续!