动态创建Lambda表达式实现高级查询



需求简介

最近这几天做的东西总算是回归咱的老本行了,给投资管理项目做一个台账的东西,就是类似我们的报表。其


中有一个功能是一个高级查询的需求,在查询条件方面大概有7、8个查询条件。需求就是如果一个条件都不输入就默


【动态创建Lambda表达式实现高级查询】认查询全部的数据,那个条件不为空的时候就在查询条件上面添加对响应字段的限制,也就是说我们在写查询条件的


时候不能写死,因为我们不知道我们到底有几个条件?到底有几个条件。所以需要我们动态的创建Lambd表达式。看


了看他们相似的功能,在实现的时候用的动态拼接SQL语句,那些SQL代码啊?看到都头疼,所以我直接放弃了,用咱


自己熟悉的知识来实现。和这个相似的功能自己在之前的《图书馆项目》中实现过,请点击我。


具体实现—小Demo

首先需要引入命名空间


using System.Linq.Expressions.Expression;



//创建一个数组用来当做例子var ints = new int []{ 1, 2 , 3 , 4 , 5 , 6 }; // 要创建形如 i => i < 5//创建参数 ivar parameter= Expression.Parameter(typeof(int),”i”); //创建常数 5var constant = Expression.Constant(5); //创建 i > 5var bin = Expression.GreaterThan(parameter,constant); //获取Lambda表达式var lambda=Expression.Lambda>(bin,parameter); //取得查询结果var query = ints.Where(lambda.Compile());




通过上面一个小Demo我们可以简单的看到动态创建Lambda表达式的雏形,下面在介绍一个比较复杂的例子。


BinaryExpression condition = null; //要构造的表达式i==1||i==2||i==3.....for (int i = 0; i < ints.Length; i++){ConstantExpression ce = Expression.Constant(i); if (condition == null){condition = Expression.Equal(parameter, ce); }else{var right = Expression.Equal(parameter, ce); condition = Expression.Or(condition, right); }}Expression> lambda = Expression.Lambda>(condition, parameter);




实体类的实现
上面都是比较简单的小例子,但是在我们项目中都是来对实体进行条件查询的,所以呢小编在下面会给大家介

绍一下如何对实体类进行构造。



//p => p.Name == "1" && p.Address == "2"ParameterExpression parameter1 = Expression.Parameter(typeof(Person), "p"); MemberExpression member1 = Expression.PropertyOrField(parameter1, "Name"); MemberExpression member2 = Expression.PropertyOrField(parameter1, "Address"),ConstantExpression constant1 = Expression.Constant("郑浩"); ConstantExpression constant2 = Expression.Constant("河北"); var query1 = Expression.Equal(member1, constant1); //Equal等于;GreaterThanOrEqual大于;LessThanOrEqual小于var query2 = Expression.Equal(member2, constant2); var query = Expression.And(query1, query2); //and 与;or或var lambda1 = Expression.Lambda(query, parameter1); var list = MethodExtend.GetUser(lambda1.Compile());



代码介绍:
1)创建表达式的开始部分:p=>


2、3)创建我们要查询的字段:p.Name和p.Address


4、5)给给变量赋值,这些值和变量可以任意匹配


6、7)匹配查询条件和对应的值:p.Name=="郑浩";p.Address=="河北"


8、9)连接查询条件; p.Name=="郑浩"&&p.Address=="河北"


10)创建最后的查询条件:p=>p.Name=="郑浩"&&p.Address=="河北"


11)最后执行查询条件



项目实战
我首先创建了一个接口,因为这个功能不是我自己使用,还有别的模块也需要这个功能;



namespace Seagull2.Investment.WebApi { /// /// 可实现表达式接口 /// public interface IExpressionable where T : class { /// /// 创建表达式 /// /// Expression> CreateExpression(); } }




我将创建Landa表达式的部分放在module中,这个module是和界面对应,接收界面传递参数,代码如下:



public class RealEstateProjectCondition : IExpressionable {/// /// 项目所在省份 /// public string ProjectOfProvince { get; set; } /// /// 项目所在城市 /// public string ProjectOfCity { get; set; }/// /// 项目业态名称 /// public string ProjectFormatName { get; set; }/// /// 所属业务团队 /// public string BusiGroup { get; set; } /// /// 项目所处阶段 /// public string PrjStageCode { get; set; } /// /// 申请起始日期 /// public DateTimeOffset? ApplyStartDate { get; set; } /// /// 申请起始日期 /// public DateTimeOffset? ApplyEndDate { get; set; } /// /// 基金规模(亿元)上线 /// public decimal? StartFundSize { get; set; } /// /// 基金规模(亿元)下线 /// public decimal? EndFundSize { get; set; }/// /// 创建房地产投资查询条件表达式 /// /// public Expression> CreateExpression() { ParameterExpression parameter = Expression.Parameter(typeof(View_RealEstateProject), "p"); //项目类型编码 ConstantExpression constantPrjTypeCode = Expression.Constant("A0BE01A2-1BE3-4AAE-8DE3-B84BB6B2A58A"); MemberExpression memberPrjTypeCode = Expression.PropertyOrField(parameter, "PrjTypeCode"); var query = Expression.Equal(memberPrjTypeCode, constantPrjTypeCode); //项目所在省份 if (!string.IsNullOrEmpty(this.ProjectOfProvince)) { ConstantExpression constantProjectOfProvince = Expression.Constant(this.ProjectOfProvince); MemberExpression memberProjectOfCity = Expression.PropertyOrField(parameter, "ProjectOfProvince"); query = Expression.And(query, Expression.Equal(memberProjectOfCity, constantProjectOfProvince)); } //项目所在城市 if (!string.IsNullOrEmpty(this.ProjectOfCity)) { ConstantExpression constantProjectOfCity = Expression.Constant(this.ProjectOfCity); MemberExpression memberProjectOfCity = Expression.PropertyOrField(parameter, "ProjectOfCity"); query = Expression.And(query, Expression.Equal(memberProjectOfCity, constantProjectOfCity)); } //项目业态名称 if (!string.IsNullOrEmpty(this.ProjectFormatName)) { ConstantExpression constantProjectFormatName = Expression.Constant(this.ProjectFormatName); MemberExpression memberProjectFormatName = Expression.PropertyOrField(parameter, "ProjectFormatName"); query = Expression.And(query, Expression.Equal(memberProjectFormatName, constantProjectFormatName)); } //所属业务团队 if (!string.IsNullOrEmpty(this.BusiGroup)) { ConstantExpression constantBusiGroup = Expression.Constant(this.BusiGroup); MemberExpression memberBusiGroup = Expression.PropertyOrField(parameter, "BusiGroup"); query = Expression.And(query, Expression.Equal(memberBusiGroup, constantBusiGroup)); } //项目所处阶段 if (!string.IsNullOrEmpty(this.PrjStageCode)) { ConstantExpression constantPrjStageCode = Expression.Constant(this.PrjStageCode); MemberExpression memberPrjStageCode = Expression.PropertyOrField(parameter, "PrjStageCode"); query = Expression.And(query, Expression.Equal(memberPrjStageCode, constantPrjStageCode)); } //申请开始时间 if (this.ApplyStartDate.HasValue) { ConstantExpression constantApplyStartDate = Expression.Constant(this.ApplyStartDate.Value); MemberExpression memberApplyStartDate = Expression.PropertyOrField(parameter, "ApplyDate"); query = Expression.And(query, Expression.GreaterThanOrEqual(memberApplyStartDate, constantApplyStartDate)); } //申请结束时间 if (this.ApplyEndDate.HasValue) { ConstantExpression constantApplyEndDate = Expression.Constant(this.ApplyEndDate.Value); MemberExpression memberApplyEndDate = Expression.PropertyOrField(parameter, "ApplyDate"); query = Expression.And(query, Expression.LessThanOrEqual(memberApplyEndDate, constantApplyEndDate)); } //投资规模(亿元)上线 if (this.StartFundSize.HasValue) { ConstantExpression constantStartFundSize = Expression.Constant(this.StartFundSize.Value); MemberExpression memberStartFundSize = Expression.PropertyOrField(parameter, "FundSize"); query = Expression.And(query, Expression.GreaterThanOrEqual(memberStartFundSize, constantStartFundSize)); } //投资规模(亿元)下线 if (this.EndFundSize.HasValue) { ConstantExpression constantEndFundSize = Expression.Constant(this.EndFundSize.Value); MemberExpression memberEndFundSize = Expression.PropertyOrField(parameter, "FundSize"); query = Expression.And(query, Expression.LessThanOrEqual(memberEndFundSize, constantEndFundSize)); } //版本结束时间 ConstantExpression constantVesionEndTime = Expression.Constant(null); MemberExpression memberVesionEndTime = Expression.PropertyOrField(parameter, "VersionEndTime"); query = Expression.And(query, Expression.Equal(memberVesionEndTime, constantVesionEndTime)); //有效性 ConstantExpression constantValidStatus = Expression.Constant(true); MemberExpression memberValidStatus = Expression.PropertyOrField(parameter, "ValidStatus"); query = Expression.And(query, Expression.Equal(memberValidStatus, constantValidStatus)); return Expression.Lambda>(query, parameter); } }}


这样我们的controller和service都非常的简单明了,把查询条件作为实体的一部分。


service代码:


public List LoadView_RealEstateProject(RealEstateProjectCondition condition) { using (var db = new InvestmentDbContext()) {return db.View_RealEstateProject.Where(condition.CreateExpression()).ToList(); } }


controller代码:


[HttpPost, HttpGet] public IHttpActionResult LoadQueryResult(RealEstateProjectCondition condition) { return Json(_realEstabDasbordService.LoadView_RealEstateProject(condition)); }




小结


关于动态创建Lamda表达式就给大家介绍到这,通过动态创建表达式非常方便实现高级查询,和拼接sql来说这


还是非常简单的,并且出错的几率大大降低,所以我没有采用他们类似功能的实现,所以说我们在实现某些需求的时


候需要我们好好考虑在下手写代码,能参考的东西不一定是最合适的,还需要我们自己探索一些,希望给大家带来帮


助。

    推荐阅读