使用Expression Tree构建动态LINQ查询
这篇文章介绍一个有意思的话题,也是经常被人问到的:如何构建动态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查询的更多相关文章
- 基于领域驱动设计(DDD)超轻量级快速开发架构(二)动态linq查询的实现方式
		
-之动态查询,查询逻辑封装复用 基于领域驱动设计(DDD)超轻量级快速开发架构详细介绍请看 https://www.cnblogs.com/neozhu/p/13174234.html 需求 配合Ea ...
 - dapper利用DynamicParameters构建动态参数查询
		
public static int GetTotalLogin(string username,DateTime start, DateTime end) { using (var _connecti ...
 - [C#.NET 拾遗补漏]13:动态构建LINQ查询表达式
		
最近工作中遇到一个这样的需求:在某个列表查询功能中,可以选择某个数字列(如商品单价.当天销售额.当月销售额等),再选择 小于或等于 和 大于或等于 ,再填写一个待比较的数值,对数据进行查询过滤. 如果 ...
 - LINQ 学习路程 --  查询操作 Expression Tree
		
表达式树就像是树形的数据结构,表达式树中的每一个节点都是表达式, 表达式树可以表示一个数学公式如:x<y.x.<.y都是一个表达式,并构成树形的数据结构 表达式树使lambda表达式的结构 ...
 - 动态LINQ(Lambda表达式)构建
		
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; us ...
 - 【C#表达式树 开篇】 Expression Tree - 动态语言
		
.NET 3.5中新增的表达式树(Expression Tree)特性,第一次在.NET平台中引入了"逻辑即数据"的概念.也就是说,我们可以在代码里使用高级语言的形式编写一段逻辑, ...
 - 用PredicateBuilder实现Linq动态拼接查询
		
在使用Linq查询的时候,特别是如果你在使用Entiry Framwork,有时会遇到动态查询的情况(客户的查询条件是不固定的拼接查询).我们能想到的第一方案应该是拼接SQL,的确这样是可以达到我们的 ...
 - Expression表达式树动态查询
		
在进行数据列表的查询中,我们通常会使用两种方式进行查询: linq查询 数据库sql语句查询 这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少.使用linq,可以将所有的查询条件的属性 ...
 - [转]打造自己的LINQ Provider(上):Expression Tree揭秘
		
概述 在.NET Framework 3.5中提供了LINQ 支持后,LINQ就以其强大而优雅的编程方式赢得了开发人员的喜爱,而各种LINQ Provider更是满天飞,如LINQ to NHiber ...
 
随机推荐
- 浅谈Swift集合类型
			
Swift 的集合表现形式由数组和字典组成.它可以完美的存储任何呢想存储的东西. 数组是一个同类型的序列化列表集合,它用来存储相同类型的不同值.字典也是一个数组,但它的存值方式类似于Map,通过一对一 ...
 - delphi 读写文本
			
将字符串写入txt文档,读取txt文档中的内容. //一次写字符串到文本文件,每次都会将原来的内容替换掉. procedure FilePutContents(f,s:String); // f为文件 ...
 - hdu 3951 - Coin Game(找规律)
			
这道题是有规律的博弈题目,,, 所以我们只需要找出规律来就ok了 牛人用sg函数暴力找规律,菜鸟手工模拟以求规律...[牢骚] if(m>=2) { if(n<=m) {first第一口就 ...
 - 如何利用Github+Appveyor+Nuget打造自己的.net core开源库
			
以下教程基于你有一个托管在Github上的.net core项目,如果没有的可以自己fork一个或者自己创建了默认的项目即可. 我们打开需要生成nuget包的项目中的project.json文件,有关 ...
 - Emberjs之Observer
			
Observer Person.reopen({ fullNameChanged: Ember.observer('fullName', function() { // deal with the c ...
 - 上层建筑——DOM元素的特性与属性(dojo/dom-prop)
			
上一篇讲解dojo/dom-attr的文章中我们知道在某些情况下,attr模块中会交给prop模块来处理.比如: textContent.innerHTML.className.htmlFor.val ...
 - PPT嵌入字体的方法
			
使用ppt的时候,很多时候会使用一些特殊字体,在其他计算机上无法正常显示.这个时候就需要导出PPT的时候进行字体嵌入. 1.1 常规方法 所谓常规方法,是指那些字体的许可协议允许随意分发,我们才能导出 ...
 - Do带你解析:原生APP与web APP的区别
			
对于DeviceOne原生跨平台APP与WEB APP的区别,很多人还不是很清楚,下面就让小编来简单介绍DeviceOne原生APP的功能以及与WEB APP的区别. 定义,什么是原生APP和web ...
 - [.net 面向对象编程基础] (10) 类的成员(字段、属性、方法)
			
[.net 面向对象编程基础] (10) 类的成员(字段.属性.方法) 前面定义的Person的类,里面的成员包括:字段.属性.方法.事件等,此外,前面说的嵌套类也是类的成员. a.类的成员为分:静态 ...
 - Windows  Azure Service Bus Topics实现系统松散耦合
			
前言 Windows Azure中的服务总线(Service Bus)提供了多种功能, 包括队列(Queue), 主题(Topic),中继(Relay),和通知中心(Notification Hub) ...