这篇文章介绍一个有意思的话题,也是经常被人问到的:如何构建动态LINQ查询?所谓动态,主要的意思在于查询的条件可以随机组合,动态添加,而不是固定的写法。这个在很多系统开发过程中是非常有用的。

我这里给的一个解决方案是采用Expression Tree来构建。

其实这个技术很早就有,在.NET Framework 3.5开始引入。之前也有不少同学写过很多不错的理论性文章。我自己当年学习这个,觉得最好的几篇文章是由"装配脑袋"同学写的。【有时间请仔细阅读这些入门指南,做点练习基本就能理解】

Expression Tree上手指南 (一) - 装配脑袋 - 博客园

Expression Tree 上手指南 (二) - 装配脑袋 - 博客园

Expression Tree 上手指南 (三) - 装配脑袋 - 博客园

 

我下面给出的这个实例,希望能帮助大家更加深入理解这个技术,并且结合常见的LINQ to SQL来实现动态的查询。

下面这个查询,大家应该都很眼熟

如果我们的条件是固定的,例如上例中,一共有两个条件,而且条件的逻辑判断也都是确定的,那么上面这样写很容易就能得到我们的结果。

但,问题是,如果我们的条件不是固定的呢?如果你需要根据用户的选择,然后动态构造一个查询呢?

我看过很多人做的一些通用查询界面,为了应对用户希望自主选择条件的这个需求,他们的做法往往就是用"拼接查询字符串"的做法来实现。这种方法勉强能实现要求,但性能和可维护性方面都相当差。

如果你了解了Expression Tree,那么上面这个查询可以修改为下面这样:

 

由此可见,掌握了这个技术的话,那么以后写动态查询应该会如虎添翼,至少多了一种很好的思路。

顺便说一下,这个技术和反射有点类似,属于比较底层的技术,掌握了将对大家的编程能力会有所提升。

值得一说的是,就算是我们第一种写法,内部的实现也是使用Expression Tree来实现的,有兴趣的同学可以看看如下的IL代码。

IL_0001: ldarg.0

IL_0002: call
LINQPad.User.TypedDataContext.get_Employees

IL_0007: ldtoken
LINQPad.User.Employees

IL_000C: call
System.Type.GetTypeFromHandle

IL_0011: ldstr
"x"

IL_0016: call
System.Linq.Expressions.Expression.Parameter

IL_001B: stloc.1
// CS$0$0000

IL_001C: ldloc.1
// CS$0$0000

IL_001D: ldtoken
LINQPad.User.Employees.EmployeeID

IL_0022: call
System.Reflection.FieldInfo.GetFieldFromHandle

IL_0027: call
System.Linq.Expressions.Expression.Field

IL_002C: ldc.i4.5

IL_002D: box
System.Int32

IL_0032: ldtoken
System.Int32

IL_0037: call
System.Type.GetTypeFromHandle

IL_003C: call
System.Linq.Expressions.Expression.Constant

IL_0041: call
System.Linq.Expressions.Expression.GreaterThan

IL_0046: ldloc.1
// CS$0$0000

IL_0047: ldtoken
LINQPad.User.Employees.Title

IL_004C: call
System.Reflection.FieldInfo.GetFieldFromHandle

IL_0051: call
System.Linq.Expressions.Expression.Field

IL_0056: ldstr
"Sales Representative"

IL_005B: ldtoken
System.String

IL_0060: call
System.Type.GetTypeFromHandle

IL_0065: call
System.Linq.Expressions.Expression.Constant

IL_006A: ldc.i4.0

IL_006B: ldtoken
System.String.op_Equality

IL_0070: call
System.Reflection.MethodBase.GetMethodFromHandle

IL_0075: castclass
System.Reflection.MethodInfo

IL_007A: call
System.Linq.Expressions.Expression.Equal

IL_007F: call
System.Linq.Expressions.Expression.AndAlso

IL_0084: ldc.i4.1

IL_0085: newarr
System.Linq.Expressions.ParameterExpression

IL_008A: stloc.2
// CS$0$0001

IL_008B: ldloc.2
// CS$0$0001

IL_008C: ldc.i4.0

IL_008D: ldloc.1
// CS$0$0000

IL_008E: stelem.ref

IL_008F: ldloc.2
// CS$0$0001

IL_0090: call
System.Linq.Expressions.Expression.Lambda

IL_0095: call
System.Linq.Queryable.Where

IL_009A: stloc.0
// query

IL_009B: ldloc.0
// query

IL_009C: call
LINQPad.Extensions.Dump

 

使用Expression Tree构建动态LINQ查询的更多相关文章

  1. 基于领域驱动设计(DDD)超轻量级快速开发架构(二)动态linq查询的实现方式

    -之动态查询,查询逻辑封装复用 基于领域驱动设计(DDD)超轻量级快速开发架构详细介绍请看 https://www.cnblogs.com/neozhu/p/13174234.html 需求 配合Ea ...

  2. dapper利用DynamicParameters构建动态参数查询

    public static int GetTotalLogin(string username,DateTime start, DateTime end) { using (var _connecti ...

  3. [C#.NET 拾遗补漏]13:动态构建LINQ查询表达式

    最近工作中遇到一个这样的需求:在某个列表查询功能中,可以选择某个数字列(如商品单价.当天销售额.当月销售额等),再选择 小于或等于 和 大于或等于 ,再填写一个待比较的数值,对数据进行查询过滤. 如果 ...

  4. LINQ 学习路程 -- 查询操作 Expression Tree

    表达式树就像是树形的数据结构,表达式树中的每一个节点都是表达式, 表达式树可以表示一个数学公式如:x<y.x.<.y都是一个表达式,并构成树形的数据结构 表达式树使lambda表达式的结构 ...

  5. 动态LINQ(Lambda表达式)构建

    using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; us ...

  6. 【C#表达式树 开篇】 Expression Tree - 动态语言

    .NET 3.5中新增的表达式树(Expression Tree)特性,第一次在.NET平台中引入了"逻辑即数据"的概念.也就是说,我们可以在代码里使用高级语言的形式编写一段逻辑, ...

  7. 用PredicateBuilder实现Linq动态拼接查询

    在使用Linq查询的时候,特别是如果你在使用Entiry Framwork,有时会遇到动态查询的情况(客户的查询条件是不固定的拼接查询).我们能想到的第一方案应该是拼接SQL,的确这样是可以达到我们的 ...

  8. Expression表达式树动态查询

    在进行数据列表的查询中,我们通常会使用两种方式进行查询: linq查询 数据库sql语句查询 这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少.使用linq,可以将所有的查询条件的属性 ...

  9. [转]打造自己的LINQ Provider(上):Expression Tree揭秘

    概述 在.NET Framework 3.5中提供了LINQ 支持后,LINQ就以其强大而优雅的编程方式赢得了开发人员的喜爱,而各种LINQ Provider更是满天飞,如LINQ to NHiber ...

随机推荐

  1. Oracle 两个表之间更新的实现

    Oracle 两个表之间更新的实现   来源:互联网 作者:佚名 时间:2014-04-23 21:39 Oracle中,如果跨两个表进行更新,Sql语句写成这样,Oracle 不会通过.查了资料,S ...

  2. 安利eclipse插件之log4E

    敲完代码之后,据说要加注释.加log:OTL~~~~~~~~,在我仰天长叹之际,师父发给我了一个插件压缩包,解压-->拷贝-->重启-->了事.安装方法已经如此之便捷,简直是我辈懒癌 ...

  3. JavaScript 基础第五天

    一.引言 前面我们讨论了函数的一些基本概念,因为函数在任何一门语言之中都是很重要所以还是要好好学.昨天打开博客的时候看到有人私信我的JavaScript写错了,我定睛一看果然写错了.对此我表示很抱歉, ...

  4. ubuntu 14.04 下svn + apache2 配置

    1.svn的配置 sudo apt-get install subversion // 安装svn mkdir /home/svn // 创建仓库 svnadmin create /home/svn/ ...

  5. Java 对象内存占用

    java基本类型及对象占用的内存大小 请参考下面文章 原始类型及对象占用的内存大小 http://www.javamex.com/tutorials/memory/object_memory_usag ...

  6. 在.net中使用aquiles访问Cassandra(二)

    上文中我们已经建立了项目的基本结构,今天实现数据的修改.在NoSQL中,通常添加和修改都认为是对数据的一种Mutation.   1.建立描述修改Row的实体. public class RowMut ...

  7. [ZigBee] 8、ZigBee之UART剖析·二(串口收发)

    前言:上一节讲UART基本知识介绍完了,并深入剖析了一个串口发送工程,本节将进一步介绍串口收发! 1.初始化 在串口初始化部分,和上一节不同的地方是: 51 U0CSR |= 0x40; //允许接收 ...

  8. 透析Express.js

    前言 最近,本屌在试用Node.js,在寻找靠谱web框架时发现了Express.js.Express.js在Node.js社区中是比较出名web框架,而它的定位是“minimal and flexi ...

  9. Devexpress 等待窗体

    加载窗体以及等待窗体 程序加载时,需要等待加载完成后在显示 窗体显示顺序 1. 给用户看的等待窗体 2. 加载完成后的主窗体 代码如下: 1. 等待窗体代码 #region using using S ...

  10. Redis中5种数据结构的使用场景介绍

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/108.html?1455861435 一.redis 数据结构使用场景 原 ...