关于Expression表达式树的拼接

最近在做项目中遇到一个问题,需求是这样的:

我要对已经存在的用户进行检索,可以根据用户的id 或者用户名其中的一部分字符来检索出来,这样就出现了三种情况 只有id,只有用户名中一部字符,或者全部都有.

我们用的MVC+EF5.0的框架,在BLL层进行查询的 时候需要构建lambda表达式来作为查询条件,但是,我们怎么来构建lambda来确定查询的条件呢?我们知道Express<Func<T,bool>>这样的一个参数可以是lambda表达式,但是这里的按条件拼接式不能使用委托链的形式的.当然还有一种解决办法,我把所有查询条件都写好,然后根据传过来的ID 或者用户名 来判断确定使用哪个..这样的判断逻辑混乱,代码冗长,我们就想找一个可以动态拼接查询条件的方法.

即按照id 或者用户名是否存在动态的来拼接查询条件.

首先我们需要知道,表达式构成部分,表达式是有两部分构成,Parameter和body,第一个是参数,第二个是表达式体,表达式体是二进制的位运算,也就是 比如(left&right)而left和right要返回的值必须是基本类型的值,也就是可以参与位运算的值.例如(a,b)=>()这个lambda表达式中,ab是参数,括号后面中是表达式体这里面返回的值只能是基本类型.我们要构建一个表达式树,主要就是构建这个表达式体,那么这个表达式体是一个什么样的类型呢 ?BinaryExpression类型,我们只需要构造这个类型,然后通过Expression.And(left,right)或者Expression.Or()这两个方法来构造即可. 这个两个方法返回值就是BinaryExpression的类型对象.然后我们在用Expression.Lambda<Func<T,bool>>(BinaryExpression,Parameter)这个方法将这个表达式树转化为lambda的表达式.这就是这个问题的 解决思路,来看看我们是怎么来实现的.

首先我们定义了一个表达式变量.

Expression<Func<UserInfo, bool>> where;

然后我们开始进行labmda的构造

接下来,我们来构造参数和必要条件,也是就lambda中的c=>()中的c

ParameterExpression param = Expression.Parameter(typeof(UserInfo), "c");//c=>//c=>c.IsDelete==false这里需要不被删除的条件MemberExpression left1 = Expression.Property(param, typeof(UserInfo).GetProperty("IsDelete"));构建c.IsDeleteConstantExpression right1 = Expression.Constant(false);//构建一个常量 falseBinaryExpression be = Expression.Equal(left1, right1);构建//c=>c.IsDelete==false 就是现在这个be了

下面 我们需要根据我们的条件 也就是id和用户名字符串来继续拼接这个表达式

首先我们来拼接c.UserId==sid

if (!string.IsNullOrEmpty(Request["sid"])){//c.UserId==sidint sid = int.Parse(Request["sid"]);//根据参数的属性构造左表达式c.UserIdMemberExpression left2 = Expression.Property(param, typeof(UserInfo).GetProperty("UserId"));//构造右表达式sidConstantExpression right2 = Expression.Constant(sid);//进行合并:cUserId==sidBinaryExpression where2 = Expression.Equal(left2, right2);//将这个条件与上一个条件进行与合并:c.IsDelete==false && c.UserId==sidbe = Expression.And(be, where2);}

现在我们来拼接第二个条件

前面我们已经说过,表达式体需要返回的是可以做二进制运算的类型,但是这是个值类型字符串,该怎么办呢?

在参考了MSDN中的Expression方法中,发现有这样的一个方法.Expression.Call().

然后看了示例这个

 

究竟是用来干嘛的??

我们可以用这个call’方法 ,来调用一个类型 中的一个方法,然后产生一个MethodCallExpression类型的返回值,这样,我们来调用string. Contains方法不就可以完成我们想要的表达式了么?

且看下面的 代码

//c.UserName.Contains(sname)if (!string.IsNullOrEmpty(Request["sname"])){string sname = Request["sname"];MemberExpression left3 = Expression.Property(param, typeof(UserInfo).GetProperty("UserName"));//这里构造c.UserName这个属性表达式.ConstantExpression right3 = Expression.Constant(sname);//这里构造sname这个常量表达式MethodCallExpression where3 = Expression.Call(left3, typeof(string).GetMethod("Contains"), right3);这里我们用Call这个方法完成/c.UserName.Contains(sname)这个lambda这个表达式的实现.be = Expression.And(be, where3);//拼接刚才的be表达式,}where = Expression.Lambda<Func<UserInfo, bool>>(be, param);//生成最后需要的带参数的表达式树.

这样我们的表达式树拼接就完成了.

至于运行结果就不为大家贴图了,可以运行和lambda的结果一样.可以完成两个条件的查询.

下面,封装了这个表达式树的帮助类.大家可以参考.

public class WhereHelper<T>where T:class{private ParameterExpression param;private BinaryExpression filter;public WhereHelper(){param = Expression.Parameter(typeof (T), "c");//1==1Expression left = Expression.Constant(1);filter = Expression.Equal(left, left);}public Expression<Func<T, bool>> GetExpression(){return Expression.Lambda<Func<T, bool>>(filter,param);}public void Equal(string propertyName,object value){Expression left = Expression.Property(param, typeof (T).GetProperty(propertyName));Expression right = Expression.Constant(value, value.GetType());Expression result = Expression.Equal(left, right);filter = Expression.And(filter, result);}public void Contains(string propertyName,string value){Expression left = Expression.Property(param, typeof (T).GetProperty(propertyName));Expression right = Expression.Constant(value, value.GetType());Expression result = Expression.Call(left, typeof (string).GetMethod("Contains"), right);filter = Expression.And(filter, result);}}

当然,这个帮助类功能有限,如果有需要者,大家可以自己进行扩充.

本文所提到的技术,均为我师研究,因为他研究完之后就给我们讲解了原理和实现.我只是整理出来,给大家做

原文  http://www.cnblogs.com/ruhuaxiao/p/3773596.html

怎样使用表达式树生成动态查询

2018-01-11 12:11 by 沉睡的木木夕, 33 阅读, 0 评论, 收藏, 编辑

[翻译]怎样使用表达式树生成动态查询

在LINQ,表达式树常用于结构化查询,目标资源数据实现了 IQueryable. 例如,LINQ为关系型数据存储查询提供了 IQueryable 接口。C#编译器将这些数据源的查询编译成运行时的表达式树代码。然后查询提供程序可以遍历表达式树数据结构,并转化为合适于数据源的查询语言。

在LINQ中使用表达式树来表示分配给 Expression 类型的Lambda表达式变量。

这节主要描述了如何使用表达式树构建一个动态LINQ查询。在编译期,动态查询在特殊未知的查询的情况下是非常有用的。具体例子,一个应用程序提供了一个用户接口,最终来允许用户指定一个或多个谓词来过滤数据。为了使用LINQ查询,这种情况应用程序在运行时必须使用表达式树来构建一个LINQ查询。

Example

下面这段代码展示如何使用表达式树去围绕 IQueryable 数据源构造一个查询并运行。代码生成了一个表达式树来表示查询:

companies.Where(company => (company.ToLower() == "coho winery" || company.Length > 16)).OrderBy(company => company)

在命名空间 [System.Linq.Expressions](https://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions) 下有个工厂方法用来生成一个表达式树来表示这个查询。表示标准查询运算符方法调用的表达式将引用这些方法的 Queryable 的实现。最终表达式树被传递给 IQueryable 数据源的提供程序的 CreateQuery(Expression) 实现,以创建一个可执行的 IQueryable 类型的查询。通过枚举该查询获得结果。

Expression<Func<string, bool>> expr = name => name.Length > 10 && name.StartsWith("G");
Console.WriteLine(expr);AndAlsoModifier treeModifier = new AndAlsoModifier(); Expression modifierExpr = treeModifier.Modify(expr); Console.WriteLine(modifierExpr); string[] companies = {"Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light", "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works", "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders", "Blue Yonder Airlines", "Trey Research", "The Phone Company", "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" }; //转化IQueryable数据源 IQueryable<string> queryableData = companies.AsQueryable(); //编写表示谓词参数的表达式树 ParameterExpression pe = Expression.Parameter(typeof(string), "company"); //新建一个表达式树来表示 'company.ToLower() == "coho winery"' 的表达式 Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); Expression right = Expression.Constant("coho winery", typeof(string)); Expression e1 = Expression.Equal(left, right); //新建一个表达式树来表示 'company.Length > 16' 表达式 left = Expression.Property(pe, typeof(string).GetProperty("Length")); right = Expression.Constant(16,typeof(int)); Expression e2 = Expression.GreaterThan(left, right); //编译表达式树来生成一个表示'(company.ToLower() == "coho winery" || company.Length > 16)' 的表达式 Expression predicateBody = Expression.OrElse(e1, e2); //新建一个表达式树来表示 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))' MethodCallExpression whereCallExpresstion = Expression.Call( typeof(Queryable), "Where", new Type[] { queryableData.ElementType }, queryableData.Expression, Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe })); //排序 OrderBy(company => company) //新建一个表达式树来表示 'whereCallExpression.OrderBy(company => company)' MethodCallExpression orderCallExpresstion = Expression.Call( typeof(Queryable), "OrderBy", new Type[] { queryableData.ElementType, queryableData.ElementType }, whereCallExpresstion, Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe })); //新建一个可执行的查询表达式树 IQueryable<string> result = queryableData.Provider.CreateQuery<string>(orderCallExpresstion); //枚举结果 foreach (string company in companies) Console.WriteLine(company);

代码中在被传递到 Queryable.Where 方法中,在谓词中使用了一个固定数字。但是,你可以写一个应用程序,来编译在谓词中一个依赖于用户输入的数字变量。你也可以根据用户的输入,更改查询中调用的标准查询操作符。

编译代码

  • 创建新的控制台应用程序项目。
  • 添加对 System.Core.dll 的引用(如果尚未引用)。
  • 包括 System.Linq.Expressions 命名空间。
  • 从示例中复制代码,并将其粘贴到 Main 方法中。
希望有个生活精彩的程序人生

转载于:https://www.cnblogs.com/cjm123/p/8257461.html

关于Expression表达式树的拼接相关推荐

  1. 创建Expression表达式树动态查询

    EFCore 使用反射 根据实体的属性动态生成Expression进行查询 EFCore 的查询语法是: Expression<Func<T,bool>> condition ...

  2. C#中利用Expression表达式树进行多个Lambda表达式合并

    在上一文中介绍使用了合并两个Lambda表达式,能两个就能多个,代码如下图所示: public static class ExpressionHelp{private static Expressio ...

  3. 表达式树(EXPRESSION TREE)

    表达式树是不可执行的代码,它只是用于表示一种树状的数据结构,树上的每一个节点都表示为某种表达式类型,大概有25种表达式类型,它们都派生自Expression类.创建表达式树具体有两个优势: 1.对表达 ...

  4. C#编程(六十六)----------表达式树总结

    表达式树总结 基础 表达式树提供了一个将可执行代码转换成数据的方法.如果你要在执行代码之前修改或转换此代码,那么它是很有用的.有其是当你要将C#代码----如LINQ查询表达式转换成其他代码在另一个程 ...

  5. 第十五节:Expression表达式目录树(与委托的区别、自行拼接、总结几类实例间的拷贝)

    一. 基本介绍 回忆: 最早接触到表达式目录树(Expression)可能要追溯到几年前使用EF早期的时候,发现where方法里的参数是Expression<Func<T,bool> ...

  6. Expression 表达式目录树一

    这里有两段代码: 看一下 Where 的参数 Linq To object 的 where 方法需要的参数是 委托 Linq To Sql的 where 方法需要的参数  是被 Expression ...

  7. c#:表达式树概念及应用场景(Expression)

    环境: window 10 vs2019 16.5.1 .netcore 3.1 .Net Reflector 10 ILSpy版本6.0.0.5559-preview2 参考: 表达式树 Expre ...

  8. lambda表达式树

    一.定义: 表达式树又称为表达式目录树,以数据形式表示语言级代码.所有的数据都存储在树结构中,每个结点表示一个表达式(Expression). 二.要点: –Lambda表达式的参数类型可以忽略,因为 ...

  9. 只要十步,你就可以应用表达式树来优化动态调用

    表达式树是 .net 中一系列非常好用的类型.在一些场景中使用表达式树可以获得更好的性能和更佳的扩展性.本篇我们将通过构建一个 "模型验证器" 来理解和应用表达式树在构建动态调用方 ...

最新文章

  1. android 成长日记 8.Fragment学习之方法回调
  2. 在JDK 11中启动单文件源代码程序
  3. python pycharm打包_【转】通过PyCharm 把Python 程序打包为exe
  4. python创建单例模式_Python单例模式的四种创建方式实例解析
  5. function与感叹号!
  6. 2005.2.21 至 2005.8.8
  7. 图像处理总结:Canny边缘检测(二)
  8. 机器学习算法基础7-计算范围内素数的五种算法
  9. 目前为止微型计算机,2017年计算机一级考试题库及答案
  10. Ubuntu虚拟机安装gcc运行C程序
  11. 神器 Wineskin 基础教程
  12. 《数字孪生体技术白皮书》重磅发布(附完整版下载)
  13. 什么叫操作系统啊 | 战术后仰
  14. mandriva urpm类命令
  15. 国外android大神博客,Android手机浏览器(国外篇)横向对比评测
  16. php去掉字符串带逗号前面的字符,php 怎么去掉字符串最后一个逗号
  17. C# TreeView基本操作及其节点增,删,改(3级节点)
  18. logisim新手实验
  19. CT值(亨氏值H) 孔隙率 像素点 灰度值 RGB
  20. ONES 敏捷项目管理迭代流程图文演示

热门文章

  1. ros 机械臂复位_松下机械手原点调整方法
  2. python的运算符号使等式成立_那些年被我坑过的Python——不得不知(第二章)
  3. 2014创新工场校园招聘笔试题(9.16北京)
  4. 全网通手机插联通卡不显示无服务器,手机两张联通卡为什么只有一张有信号?其他一切正常?...
  5. 非华为电脑装华为电脑管家蓝屏和协同起不来的解决方案
  6. 如何利用python进行在线语音识别
  7. FME支持的SketchUp格式
  8. 2021浙江大学计算机学院研究生复试线,2021浙江大学
  9. 【Python百日进阶-数据分析】Day226 - plotly的仪表盘go.Indicator()
  10. AI 操控战斗机战胜飞行员?道翰天琼认知智能机器人平台API接口大脑为您揭秘。