使用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查询

时间: 2024-10-12 19:23:34

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

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

var age=23;var name="张"; StringBuilder condition = new StringBuilder(); condition.Append("where 1=1"); DynamicParameters p = new DynamicParameters(); if (age>0) { condition.Append(" AND Age>@age"); p.Add("@age"

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

表达式树就像是树形的数据结构,表达式树中的每一个节点都是表达式, 表达式树可以表示一个数学公式如:x<y.x.<.y都是一个表达式,并构成树形的数据结构 表达式树使lambda表达式的结构变得透明清楚, Expression<Func<Student, bool>> isTeenAgerExpr = s => s.age > 12 && s.age < 20; 编译器将上面的表达式翻译成下面的表达式树 Expression.Lambda

Expression表达式树动态查询

在进行数据列表的查询中,我们通常会使用两种方式进行查询: linq查询 数据库sql语句查询 这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少.使用linq,可以将所有的查询条件的属性传到后台,再根据该属性是否有值,使用where进行查询:使用存储过程,也需要将所有查询条件的属性传到后台, 再根据该属性是否有值进行sql语句的拼接.这样做在查询条件很少的时候固然没啥影响,但是有一天做查询列表的时候,本人碰到了一个查询条件高达接近10个的情况,这样再使用上述的方法固然也可以实现,但

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

概述 在.NET Framework 3.5中提供了LINQ 支持后,LINQ就以其强大而优雅的编程方式赢得了开发人员的喜爱,而各种LINQ Provider更是满天飞,如LINQ to NHibernate.LINQ to Google等,大有“一切皆LINQ”的趋势.LINQ本身也提供了很好的扩展性,使得我们可以轻松的编写属于自己的LINQ Provider. 本文为打造自己的LINQ Provider系列文章第一篇,主要介绍表达式目录树(Expression Tree)的相关知识. 认识表

用PredicateBuilder实现Linq动态拼接查询

在使用Linq查询的时候,特别是如果你在使用Entiry Framwork,有时会遇到动态查询的情况(客户的查询条件是不固定的拼接查询).我们能想到的第一方案应该是拼接SQL,的确这样是可以达到我们的目的的.但这样又会破坏程序的一至性,本来使用Entiry Framwork的目标就是用面向对象的方式操纵数据库,这样我们又要开始写SQL语句了. 其实我一开始也是这样做的直到有一天我们部门的美女程序员给我介绍LinqKit,我才开始用PredicateBuilder来拼接Predicate委托. P

动态拼接LINQ 查询条件

本文章转载:http://www.cnblogs.com/wangiqngpei557/archive/2013/02/05/2893096.html 参考:http://dotnet.9sssd.com/entfwk/art/960 http://www.cnblogs.com/killuakun/archive/2008/08/03/1259389.html http://www.cnblogs.com/snowdream/archive/2008/07/18/1246308.html 以往

多条件动态LINQ 组合查询

本文章转载:http://www.cnblogs.com/wangiqngpei557/archive/2013/02/05/2893096.html 参考:http://dotnet.9sssd.com/entfwk/art/960 http://www.cnblogs.com/killuakun/archive/2008/08/03/1259389.html http://www.cnblogs.com/snowdream/archive/2008/07/18/1246308.html 以往

使用Linq 查询数据 构建对象 select new{}

linq 查询数据 /// <summary> /// 汽车品牌及车型 /// </summary> /// <returns></returns> public string GetCarBrandSeries() { var result = from a in db.CR_BC_BRAND join c in db.CR_BC_BRAND_SERIES on a.CR_BC_BRAND_ID equals c.CR_BC_BRAND_ID select

Linq技术四:动态Linq技术 -- Linq.Expressions

前面介绍了Linq的三个方面应用:Linq to SQL, Linq to XML和Linq to Object,这篇介绍一下动态Linq的实现方式及应用场景. 命名空间: System.Linq; System.Linq.Expressions; 应用Linq的时候,我们都知道只需要Lambda表达式就行,但有些场景仅仅只使用Data Model的字段名操作是不够的或者不方便的. 场景1:假设我们需要拼接Where条件进行查询,一种方式可以拼接IQueryable的表达式.但我想像写SQL语句