当前位置 > 首页 > Asp.net

.NET深入解析LINQ框架(三:LINQ优雅的前奏)

2012-12-4 13:24:00来源:Asp.net

5】.动态LINQ查询(动态构建Expression<T>表达式树)

什么是动态LINQ查询?LINQ的编写是静态的,因为C#是基于静态类型系统原理设计的,在编写时已经确定类型,也就是在编译时就已经知道将要执行什么样的查询,条件是什么、排序方式是什么等等。那么很大一部分应用场合中我们需要根据用户的选择来查询数据源,以往我们都是通过判断的方式来拼接查询的SQL字符串,但是现在我们面对是强类型的LINQ查询,是否可以很方便的进行类似查询。其实也没有什么好神秘的,基本的实现原理是通过动态的构建表达式树来实现IQueryable<T>接口的查询。

其实动态LINQ查询所能执行的最关键的因素在于Expression<T>对象是可以被动态编译成可以执行的委托对象,委托对象是完全可以被直接使用的可执行代码段,这就为动态LINQ查询提供了基础。对于IEnumerable<T>类型的查询表达式方法都知道它的执行是不会直接接受Expression<T>类型对象的,那么动态LINQ是否能工作于IEnumerable<T>接口?其实可以的,有个很隐蔽的窍门隐藏在IQueryable<T>扩展方法对象Queryable中,也就是AsQueryable<T>方法,它返回的是一个实现了IQueryable<T>接口的EnumerableQuery对象,该对象的实现内容不是很复杂,将动态拼接的数据结构Expression<T>对象编译成可以执行的匿名函数,然后直接执行查询。[王清培版权所有,转载请给出署名]

我们来看一下EnumerableQuery对象的重点,它肯定有一个地方是将Expression<T>对象Compiler的地方。

1 private IEnumerator<T> GetEnumerator()
2 {
3 if (this.enumerable == null)
4 {
5 EnumerableRewriter rewriter = new EnumerableRewriter();
6 Expression<Func<IEnumerable<T>>> expression2 =
7 Expression.Lambda<Func<IEnumerable<T>>>(rewriter.Visit(this.expression), (IEnumerable<ParameterExpression>)null);
8 this.enumerable = expression2.Compile()(); //(1)重点
9 }
10 return this.enumerable.GetEnumerator();
11 }

在上述代码中的“(1)重点”的地方,我们很清楚的看见表达式树被动态编译后然后紧接着又被执行,这里就能看出为什么IEnumerable<T>对象需要能够被转换成IQueryable<T>对象。这样就可以消除IEnumerable<T>、IQueryable<T>这两个接口之间的动态查询瓶颈。

为什么需要动态LINQ查询,上面说过问题出在我们没办法在运行时再去编写Lambda表达式了,都知道Lambda表达式到最后就是被编译成Expression表达式树对象,所以我们可以在运行时自己动态的构建Expression对象,这样就可以将动态构建出来的表达式树对象直接传入到需要的方法中。如果查询的数据对象是IEnumerable<T>则会被动态编译成可以执行的委托然后直接执行,如果查询的是IQueryable<T>则顺其自然的被提供程序解析执行。

下面我们来看一个简单的动态查询例子:

1 //构造Student数组
2 Student[] StudentArrary = new Student[3]
3 {
4 new Student(){Name="王清培", Age=24, Sex="", Address="江苏南京"},
5 new Student(){Name="陈玉和", Age=23, Sex="", Address="江苏盐城"},
6 new Student(){Name="金源", Age=22, Sex="", Address="江苏淮安"}
7 };

这是一组数据,为了简单测试就不搞那么麻烦的Linq to Sql数据源了。我们将要通过动态的构建表达式树来做为查询的逻辑,以往我们的Lambda在这个时候派不上用场了,在运行时我们无法再去构建委托类型。

现在的需求是从界面上接受一


  • DotNetNuke 7.0 Only Weeks Away!

    2012-11-16 1:45:00

    The software industry moves at a lightning pace, and it is only through constant focus and continuo

  • .Net Web Sesssion使用不再受限

    2012-11-16 18:51:00

    可能需要做仅一次登录(别人登录过,你不能登录或强制T前一个人的登录),也有可能在想在不能使用Session的地方,比如缓存自定权限认证需要使用Session。 首先,第一思维,不应该是自定义,不管

  • 团队建设(4)-天下没有不散的筵席

    2007-3-31 12:21:00

    铁打的营盘流水的兵,团队成员们相聚一场,最终难免要离开。有的成员羽翼日渐丰满,自然要高升/跳槽;达不到考核底线的成员也需要另谋出路。 做一个开发组长,最得意的莫过于当其他部门成立开发组时,他们的老板

  • 再谈谈ADO.NET Data Service 数据格式(xml和json)

    2011-6-12 13:20:00

    去年的时候,我写过一篇文章,介绍如何让ADO.NET Data Service返回json数据格式。如果有兴趣,可以参考下面这个链接 http://www.cnblogs.com/chenxi

  • Structured Discriminator Pattern

    2007-3-22 10:10:00

    摘要: 阅读全文 bobmazelin 2007-03-22 09:19 发表评论

  • jquery文件上传插件uploadify在.NET中session丢失的解决方案

    2011-4-11 21:32:00

    基于jQuery和Flash的多文件上传插件uploadify的确很好用,具体配置和使用方法见以前的一篇文章: 《一款基于jQuery的文件上传插件(.NET版)》 。但今天在用这个插件的时候遇到了

  • DotNetNuke 5 C#版本解读之3--DNN Membership

    2010-7-26 11:50:00

    作者: Nic Pei 发表于 2010-07-25 23:20 原文链接 阅读: 653 评论: 0 好几天没写这一系列了。工作原因。。。 前面几篇: 1. D

  • 一个不被flash、select、activex遮挡的无限分级菜单

    2007-5-29 9:53:00

    摘要: 这是一个改自chromemenu的下拉菜单,不会被flash、activex、select等页面元素覆盖,并支持无限分级。 阅读全文 绝非偶然 2007-05-29 08:58

  • 揭示同步块索引(中):如何获得对象的HashCode

    2009-8-14 1:51:00

    摘要: 不起眼的同步块索引(SyncBlockIndex),占据着对象头部4个字节,几乎没有什么文档记录,但却起着举足轻重的作用。同步块索引到底是如何完成多重的职责?什么,HashCode也与这个同

  • 也谈中移动

    2009-8-18 23:04:00

    摘要: 这几天比较闲,就写了点东西,大家随便拍 上次聊到了flash,为什么我老是觉得flash会很重要,会是划互联网时代的革命性的东西。后来我又仔细的想了一下,忽然明白,flash和其他技术的不同