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

我要对已经存在的用户进行检索,可以根据用户的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.IsDelete

ConstantExpression right1 = Expression.Constant(false);//构建一个常量 false

BinaryExpression be = Expression.Equal(left1, right1);构建//c=>c.IsDelete==false 就是现在这个be了

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

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

if (!string.IsNullOrEmpty(Request["sid"]))

{

//c.UserId==sid

int sid = int.Parse(Request["sid"]);

//根据参数的属性构造左表达式c.UserId

MemberExpression left2 = Expression.Property(param, typeof(UserInfo).GetProperty("UserId"));

//构造右表达式sid

ConstantExpression right2 = Expression.Constant(sid);

//进行合并:cUserId==sid

BinaryExpression where2 = Expression.Equal(left2, right2);

//将这个条件与上一个条件进行与合并:c.IsDelete==false && c.UserId==sid

be = 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==1

             Expression left = Expression.Constant();

             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);

         }

 }

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

关于Expression表达式树的拼接的更多相关文章

  1. 介绍一个可以将Expression表达式树解析成Transact-SQL的项目Expression2Sql

    一.Expression2Sql介绍 Expression2Sql是一个可以将Expression表达式树解析成Transact-SQL的项目.简单易用,几分钟即可上手使用,因为博主在设计Expres ...

  2. 委托、匿名委托、Lambda 表达式、Expression表达式树之刨根问底

    本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景.各位看官,这里就不啰嗦了,直接上代码. 首先定义一个泛型委托类型,如下: public delegate T Function&l ...

  3. .net 系列:Expression表达式树、lambda、匿名委托 的使用

    首先定义一个泛型委托类型,如下: public delegate T Function<T>(T a, T b); 实现泛型委托的主体代码,并调用: public static strin ...

  4. .net 系列:Expression表达式树、lambda、匿名委托 的使用【转】

    https://www.cnblogs.com/nicholashjh/p/7928205.html 首先定义一个泛型委托类型,如下: public delegate T Function<T& ...

  5. Expression表达式树(C#)

    Lambda表达式: 1.下面举例通过Lambda表达式创建了一个用于验证Name的Func委托. //通过Lambda表达式创建一个对象的Name属性验证委托 Func<SearchInfo, ...

  6. .NET技术-6.0. Expression 表达式树 生成 Lambda

    .NET技术-6.0. Expression 表达式树 生成 Lambda public static event Func<Student, bool> myevent; public ...

  7. 表达式树动态拼接lambda

    动态拼接lambda表达式树   前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dappe ...

  8. Expression表达式树

    表达式树表示树状数据结构的代码,树状结构中的每个节点都是一个表达式,例如一个方法调用或类似 x < y 的二元运算 1.利用 Lambda 表达式创建表达式树 Expression<Fun ...

  9. Expression 表达式树学习整理

    整理了一下表达式树的一些东西,入门足够了 先从ConstantExpression 开始一步一步的来吧  它表示具有常量值的表达式 我们选建一个控制台应用程序 ConstantExpression _ ...

随机推荐

  1. 对TCP说三道四

    夜朦胧,人方静,无聊的人打开了无聊的电脑看到了一张无聊的图,想着想着就睡着了,梦到了人a和人b的一次聊天.        有一天,a有事情想跟b商量就问b"有时间么,想和你聊一下天" ...

  2. hive学习3(hive基本操作)

    hive基本操作 hive的数据类型 1)基本数据类型 TINYINT,SMALLINT,INT,BIGINT FLOAT/DOUBLE BOOLEAN STRING 2)复合类型 ARRAY:一组有 ...

  3. python解析json

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式. 引用 import json 编码:把一个Python对象编码转换成Json字符串 json.dumps ...

  4. InnoSetup能够实现“安装细节描述”界面吗?

    QUOTE( Example_Test.iss ) // 脚本使用了 增强版脚本编辑器 build 091218:Beta2// 编译器版本为 5.3.6.ee1 [Setup]AppName=My ...

  5. android: 创建自己的内容提供器

    我们学习了如何在自己的程序中访问其他应用程序的数据.总体来说思 路还是非常简单的,只需要获取到该应用程序的内容 URI,然后借助 ContentResolver 进行CRUD 操作就可以了.可是你有没 ...

  6. 小白学数据分析----->什么才是留存率的关键?

    最近花了很多的时间在体验各种游戏,从火爆的卡牌,到策略,RPG等等,有一个问题在影响我,什么才是留存率的关键?今天就先讨论一些我的想法. 留存率已经成为大家最常提到的词汇,也是拿出来show一下的武器 ...

  7. Simple-RTMP-Server 服务器搭建

    Simple-RTMP-Server 服务器搭建 1. 服务器镜像获取 github源码地址 git clone https://github.com/winlinvip/simple-rtmp-se ...

  8. 支付宝支付后回调通知中responseTxt=true isSign=False可能的问题

    在做支付宝的二维码扫码支付功能,生成二维码成功,扫描后也能付款,付款后也能回调通知到我的页面,但是验证签名的时候出错,找了好久终于找到是什么原因: 引用 1. 用的RSA签名验证,默认密钥纯字符,并不 ...

  9. 【规范】javascript 变量命名规则

    javascript 有三大经典的变量命名法:匈牙利命名法,驼峰式命名法和帕斯卡命名法.今天主要介绍下这三种命名方式. 匈牙利命名法 语法 变量名 = 类型 + 对象描述 类型指变量的类型 对象描述指 ...

  10. 画六边形-mat

    %% theta = linspace(0,2*pi,7); D=2; %边长 X=1; %中心横坐标 Y=2; %中心纵坐标 plot(D*cos(theta)+X,D*sin(theta) + Y ...