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

需求简介

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

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

认查询全部的数据,那个条件不为空的时候就在查询条件上面添加对响应字段的限制,也就是说我们在写查询条件的

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

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

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

   具体实现—小Demo

   首先需要引入命名空间


   using System.Linq.Expressions.Expression;

   

[csharp] view plain copy
 
 print?
  1. //创建一个数组用来当做例子  
  2.   
  3.   
  4.    var ints = new int []{ 1, 2 , 3 , 4 , 5 , 6 };  
  5.   
  6.   
  7.    // 要创建形如 i => i < 5  
  8.   
  9.   
  10.    //创建参数 i  
  11.   
  12.   
  13. var parameter  = Expression.Parameter(typeof(int),”i”);  
  14.   
  15.   
  16. //创建常数 5  
  17.   
  18.   
  19. var constant = Expression.Constant(5);  
  20.   
  21.   
  22. //创建 i > 5  
  23.   
  24.   
  25. var bin = Expression.GreaterThan(parameter,constant);  
  26.   
  27.   
  28. //获取Lambda表达式  
  29.   
  30.   
  31. var lambda=Expression.Lambda<Func<Int32,Boolean>>(bin,parameter);  
  32.   
  33.   
  34. //取得查询结果  
  35.   
  36.   
  37. var query = ints.Where(lambda.Compile());  

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

[csharp] view plain copy
 
 print?
  1. BinaryExpression condition = null;  
  2.   
  3. //要构造的表达式i==1||i==2||i==3.....  
  4.   
  5. for (int i = 0; i < ints.Length; i++)  
  6.   
  7. {  
  8.   
  9.       ConstantExpression ce = Expression.Constant(i);  
  10.   
  11.       if (condition == null)  
  12.   
  13.       {  
  14.   
  15.            condition = Expression.Equal(parameter, ce);  
  16.   
  17.       }  
  18.   
  19.       else  
  20.   
  21.       {  
  22.   
  23.            var right = Expression.Equal(parameter, ce);  
  24.   
  25.            condition = Expression.Or(condition, right);  
  26.   
  27.       }  
  28.   
  29. }  
  30.   
  31. Expression<Func<Int32, Boolean>> lambda = Expression.Lambda<Func<Int32, Boolean>>(condition, parameter);  

   实体类的实现


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

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

[csharp] view plain copy
 
 print?
  1. //p => p.Name == "1" && p.Address == "2"  
  2.   
  3.            ParameterExpression parameter1 = Expression.Parameter(typeof(Person), "p");  
  4.           
  5.     MemberExpression member1 = Expression.PropertyOrField(parameter1, "Name");  
  6.            
  7.     MemberExpression member2 =  Expression.PropertyOrField(parameter1, "Address"),  
  8.            
  9.            ConstantExpression constant1 = Expression.Constant("郑浩");  
  10.           
  11.            ConstantExpression constant2 = Expression.Constant("河北");  
  12.            
  13.         var query1 = Expression.Equal(member1, constant1);//Equal等于;GreaterThanOrEqual大于;LessThanOrEqual小于  
  14.   
  15.            var query2 = Expression.Equal(member2, constant2);  
  16.   
  17.            var query = Expression.And(query1, query2);//and 与;or或  
  18.   
  19.            var lambda1 = Expression.Lambda<Func<Person, Boolean>>(query, parameter1);  
  20.   
  21.            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)最后执行查询条件

   项目实战

 

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

[csharp] view plain copy
 
 print?
  1. namespace Seagull2.Investment.WebApi  
  2. {  
  3.     /// <summary>  
  4.     /// 可实现表达式接口  
  5.     /// </summary>  
  6.     public interface IExpressionable<T> where T : class  
  7.     {  
  8.         /// <summary>  
  9.         /// 创建表达式  
  10.         /// </summary>  
  11.         /// <returns></returns>  
  12.         Expression<Func<T, bool>> CreateExpression();  
  13.     }  
  14. }  



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

[csharp] view plain copy
 
 print?
  1. public class RealEstateProjectCondition : IExpressionable<View_RealEstateProject>  
  2.    {  
  3.          
  4.        /// <summary>  
  5.        /// 项目所在省份  
  6.        /// </summary>  
  7.        public string ProjectOfProvince { get; set; }  
  8.        /// <summary>  
  9.        /// 项目所在城市  
  10.        /// </summary>  
  11.        public string ProjectOfCity { get; set; }  
  12.   
  13.        /// <summary>  
  14.        /// 项目业态名称  
  15.        /// </summary>  
  16.        public string ProjectFormatName { get; set; }  
  17.   
  18.        /// <summary>  
  19.        /// 所属业务团队  
  20.        /// </summary>  
  21.        public string BusiGroup { get; set; }  
  22.        /// <summary>  
  23.        /// 项目所处阶段  
  24.        /// </summary>  
  25.        public string PrjStageCode { get; set; }  
  26.        /// <summary>  
  27.        /// 申请起始日期  
  28.        /// </summary>  
  29.        public DateTimeOffset? ApplyStartDate { get; set; }  
  30.        /// <summary>  
  31.        /// 申请起始日期  
  32.        /// </summary>  
  33.        public DateTimeOffset? ApplyEndDate { get; set; }  
  34.        /// <summary>  
  35.        /// 基金规模(亿元)上线  
  36.        /// </summary>  
  37.        public decimal? StartFundSize { get; set; }  
  38.        /// <summary>  
  39.        /// 基金规模(亿元)下线  
  40.        /// </summary>  
  41.        public decimal? EndFundSize { get; set; }  
  42.   
  43.        /// <summary>  
  44.        /// 创建房地产投资查询条件表达式  
  45.        /// </summary>  
  46.        /// <returns></returns>  
  47.        public Expression<Func<View_RealEstateProject, bool>> CreateExpression()  
  48.        {  
  49.            ParameterExpression parameter = Expression.Parameter(typeof(View_RealEstateProject), "p");  
  50.            //项目类型编码  
  51.            ConstantExpression constantPrjTypeCode = Expression.Constant("A0BE01A2-1BE3-4AAE-8DE3-B84BB6B2A58A");  
  52.            MemberExpression memberPrjTypeCode = Expression.PropertyOrField(parameter, "PrjTypeCode");  
  53.            var query = Expression.Equal(memberPrjTypeCode, constantPrjTypeCode);  
  54.            //项目所在省份  
  55.            if (!string.IsNullOrEmpty(this.ProjectOfProvince))  
  56.            {  
  57.                ConstantExpression constantProjectOfProvince = Expression.Constant(this.ProjectOfProvince);  
  58.                MemberExpression memberProjectOfCity = Expression.PropertyOrField(parameter, "ProjectOfProvince");  
  59.                query = Expression.And(query, Expression.Equal(memberProjectOfCity, constantProjectOfProvince));  
  60.            }  
  61.            //项目所在城市  
  62.            if (!string.IsNullOrEmpty(this.ProjectOfCity))  
  63.            {  
  64.                ConstantExpression constantProjectOfCity = Expression.Constant(this.ProjectOfCity);  
  65.                MemberExpression memberProjectOfCity = Expression.PropertyOrField(parameter, "ProjectOfCity");  
  66.                query = Expression.And(query, Expression.Equal(memberProjectOfCity, constantProjectOfCity));  
  67.   
  68.            }  
  69.            //项目业态名称  
  70.            if (!string.IsNullOrEmpty(this.ProjectFormatName))  
  71.            {  
  72.                ConstantExpression constantProjectFormatName = Expression.Constant(this.ProjectFormatName);  
  73.                MemberExpression memberProjectFormatName = Expression.PropertyOrField(parameter, "ProjectFormatName");  
  74.                query = Expression.And(query, Expression.Equal(memberProjectFormatName, constantProjectFormatName));  
  75.   
  76.            }  
  77.            //所属业务团队  
  78.            if (!string.IsNullOrEmpty(this.BusiGroup))  
  79.            {  
  80.                ConstantExpression constantBusiGroup = Expression.Constant(this.BusiGroup);  
  81.                MemberExpression memberBusiGroup = Expression.PropertyOrField(parameter, "BusiGroup");  
  82.                query = Expression.And(query, Expression.Equal(memberBusiGroup, constantBusiGroup));  
  83.   
  84.            }  
  85.            //项目所处阶段  
  86.            if (!string.IsNullOrEmpty(this.PrjStageCode))  
  87.            {  
  88.                ConstantExpression constantPrjStageCode = Expression.Constant(this.PrjStageCode);  
  89.                MemberExpression memberPrjStageCode = Expression.PropertyOrField(parameter, "PrjStageCode");  
  90.                query = Expression.And(query, Expression.Equal(memberPrjStageCode, constantPrjStageCode));  
  91.   
  92.            }  
  93.            //申请开始时间  
  94.            if (this.ApplyStartDate.HasValue)  
  95.            {  
  96.                ConstantExpression constantApplyStartDate = Expression.Constant(this.ApplyStartDate.Value);  
  97.                MemberExpression memberApplyStartDate = Expression.PropertyOrField(parameter, "ApplyDate");  
  98.                query = Expression.And(query, Expression.GreaterThanOrEqual(memberApplyStartDate, constantApplyStartDate));  
  99.            }  
  100.            //申请结束时间  
  101.            if (this.ApplyEndDate.HasValue)  
  102.            {  
  103.                ConstantExpression constantApplyEndDate = Expression.Constant(this.ApplyEndDate.Value);  
  104.                MemberExpression memberApplyEndDate = Expression.PropertyOrField(parameter, "ApplyDate");  
  105.                query = Expression.And(query, Expression.LessThanOrEqual(memberApplyEndDate, constantApplyEndDate));  
  106.            }  
  107.            //投资规模(亿元)上线  
  108.            if (this.StartFundSize.HasValue)  
  109.            {  
  110.                ConstantExpression constantStartFundSize = Expression.Constant(this.StartFundSize.Value);  
  111.                MemberExpression memberStartFundSize = Expression.PropertyOrField(parameter, "FundSize");  
  112.                query = Expression.And(query, Expression.GreaterThanOrEqual(memberStartFundSize, constantStartFundSize));  
  113.            }  
  114.            //投资规模(亿元)下线  
  115.            if (this.EndFundSize.HasValue)  
  116.            {  
  117.                ConstantExpression constantEndFundSize = Expression.Constant(this.EndFundSize.Value);  
  118.                MemberExpression memberEndFundSize = Expression.PropertyOrField(parameter, "FundSize");  
  119.                query = Expression.And(query, Expression.LessThanOrEqual(memberEndFundSize, constantEndFundSize));  
  120.            }  
  121.            //版本结束时间  
  122.            ConstantExpression constantVesionEndTime = Expression.Constant(null);  
  123.            MemberExpression memberVesionEndTime = Expression.PropertyOrField(parameter, "VersionEndTime");  
  124.            query = Expression.And(query, Expression.Equal(memberVesionEndTime, constantVesionEndTime));  
  125.            //有效性  
  126.            ConstantExpression constantValidStatus = Expression.Constant(true);  
  127.            MemberExpression memberValidStatus = Expression.PropertyOrField(parameter, "ValidStatus");  
  128.            query = Expression.And(query, Expression.Equal(memberValidStatus, constantValidStatus));  
  129.   
  130.            return Expression.Lambda<Func<View_RealEstateProject, bool>>(query, parameter);  
  131.        }  
  132.    }  


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

   service代码:

[csharp] view plain copy
 
 print?
  1. public List<View_RealEstateProject> LoadView_RealEstateProject(RealEstateProjectCondition condition)  
  2.         {  
  3.             using (var db = new InvestmentDbContext())  
  4.             {  
  5.                   
  6.                 return db.View_RealEstateProject.Where(condition.CreateExpression()).ToList();  
  7.             }  
  8.         }  

   

   controller代码:

[csharp] view plain copy
 
 print?
  1. [HttpPost, HttpGet]  
  2.         public IHttpActionResult LoadQueryResult(RealEstateProjectCondition condition)  
  3.         {             
  4.             return Json(_realEstabDasbordService.LoadView_RealEstateProject(condition));  
  5.         }  



    小结

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

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

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

助。

http://blog.csdn.net/hao134838/article/details/51404151

原文地址:https://www.cnblogs.com/sjqq/p/8042378.html