使用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 ...
随机推荐
- Python成长笔记 - 基础篇 (十一)
回顾: 线程:资源的集合:内存共享,两个或多个线程同时修改一份数据时,造成结果可能不正确,必须加锁 进程:运行的最小单元 守护进程:在start之前设置setDemo() 队列queue:作用解耦,使 ...
- ubuntu12.04网络配置
1.配置/etc/network/interfaces #静态IP地址 auto lo iface lo inet loopback #loopback虚拟网络设备,使TCP/IP能以127.0.0. ...
- 多语言配置--LogisticsPlatform物流平台系统
先看:LanguageProvider.cs 中几个主要方法 1.读取默认语言 附user.ini文件: 2.获取语言类型 附LanguageType.xml 3.读取语言资源 附: 看ILa ...
- 【IOS】异步调用--- 简单使用记录
/×× ×实现功能:店铺被删除后,先显示提示toast.然后,页面休眠5秒后,再返回到店铺列表页面.×/ - (void)processDeleteShopError { _isLoadingData ...
- Use Hibernate core API
For Hibernate configuration, We can use hibernate.cfg.xml file to configure: <?xml version='1.0' ...
- Intellij IDEA工具Java web 环境搭建
Java web 环境搭建 环境依赖 操作系统:Windows 7 64位 开发工具:IntelliJ IDEA 13.1.4 开发工具依赖环境 JDK版本:1.7+ 开发工具依赖插件 包管理:Mav ...
- IIS部署Nodejs步骤
需要iis的url重写插件 安装iisnode 配置文件 rewrite 节点需要url重写插件支持 node.exe 路径是你安装的路径 interceptor.js 是你安装iisnode的路径 ...
- Xamarin开发Android笔记:拍照或相册选取图片角度问题
在开发Android应用的时候,可能会遇到类似微信朋友圈中拍照或相册选取图片的场景,拍照或选取图片之后在显示的时候却发现图片的角度不对,明明是竖版拍照,显示出来缺失躺着的. 这是因为在某些特定手机上例 ...
- Storm-源码分析- Storm中Zookeeper的使用
在backtype.storm.cluster.clj中, 定义了storm对于Zookeeper的使用 ClusterState 首先定义操作Zookeeper集群的interface (def ...
- objective-c(内存管理)
本文主要记录objective-c 内存管理的知识点: 1.objective-c的对象都是分配内存在堆上,与C的mallock和C++的new类似,只有int等系统变量分配内存在栈上: 2.obje ...