• 动态创建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

  • 相关阅读:
    touchMove VS touchCancel
    svg viewbox 作用
    reactjs reactLink
    放开linux下的端口
    运算符重载函数作为类成员函数和友元函数 (转)
    MBean和MXBean 区别
    transfer-encoding
    CSRF
    vue知识拓展
    居中
  • 原文地址:https://www.cnblogs.com/sjqq/p/8042378.html
Copyright © 2020-2023  润新知