关闭

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

标签: lambda高级查询EF
10709人阅读 评论(63) 收藏 举报
分类:


   需求简介


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


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


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


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


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


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


   具体实现—小Demo


   首先需要引入命名空间


   using System.Linq.Expressions.Expression;


   

//创建一个数组用来当做例子


   var ints = new int []{ 1, 2 , 3 , 4 , 5 , 6 };


   // 要创建形如 i => i < 5


   //创建参数 i


var parameter  = Expression.Parameter(typeof(int),”i”);


//创建常数 5


var constant = Expression.Constant(5);


//创建 i > 5


var bin = Expression.GreaterThan(parameter,constant);


//获取Lambda表达式


var lambda=Expression.Lambda<Func<Int32,Boolean>>(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<Func<Int32, Boolean>> lambda = Expression.Lambda<Func<Int32, Boolean>>(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<Func<Person, Boolean>>(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
{
    /// <summary>
    /// 可实现表达式接口
    /// </summary>
    public interface IExpressionable<T> where T : class
    {
        /// <summary>
        /// 创建表达式
        /// </summary>
        /// <returns></returns>
        Expression<Func<T, bool>> CreateExpression();
    }
}


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


 public class RealEstateProjectCondition : IExpressionable<View_RealEstateProject>
    {
        
        /// <summary>
        /// 项目所在省份
        /// </summary>
        public string ProjectOfProvince { get; set; }
        /// <summary>
        /// 项目所在城市
        /// </summary>
        public string ProjectOfCity { get; set; }

        /// <summary>
        /// 项目业态名称
        /// </summary>
        public string ProjectFormatName { get; set; }

        /// <summary>
        /// 所属业务团队
        /// </summary>
        public string BusiGroup { get; set; }
        /// <summary>
        /// 项目所处阶段
        /// </summary>
        public string PrjStageCode { get; set; }
        /// <summary>
        /// 申请起始日期
        /// </summary>
        public DateTimeOffset? ApplyStartDate { get; set; }
        /// <summary>
        /// 申请起始日期
        /// </summary>
        public DateTimeOffset? ApplyEndDate { get; set; }
        /// <summary>
        /// 基金规模(亿元)上线
        /// </summary>
        public decimal? StartFundSize { get; set; }
        /// <summary>
        /// 基金规模(亿元)下线
        /// </summary>
        public decimal? EndFundSize { get; set; }

        /// <summary>
        /// 创建房地产投资查询条件表达式
        /// </summary>
        /// <returns></returns>
        public Expression<Func<View_RealEstateProject, bool>> 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<Func<View_RealEstateProject, bool>>(query, parameter);
        }
    }

}

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


   service代码:


public List<View_RealEstateProject> 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来说这


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


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


助。
   

2
0
查看评论

使用Expression动态创建lambda表达式

using System; using System.Linq.Expressions; using System.Reflection;namespace Helper { public class LambdaHelper { /// <summary>...
  • tiana0
  • tiana0
  • 2016-11-17 09:56
  • 4523

几种编程语言的Lambda Expression初探

几乎所有主流开发语言支持编程语言都提供了对Lambda Expression的支持,毕竟好用嘛。初探下Python、C++、C#、PHP以及Javascript的Lambda Expression。
  • kikaylee
  • kikaylee
  • 2016-05-12 21:05
  • 899

Lambda表达式 c# 经验谈:巧用Expression表达式 解决类似于sql中 select in 的查询(适合于中小型项目)

我们在项目经常会碰到一些特殊需求 例如下拉框是复选的,查询条件是根据下拉框中复选项进行拼接 看到此图后大家肯定会说,这很简单嘛 将所有的选项 拼成“'1-3','5-9'”  然后放到 in 的字句后面,一查就出来了。 这样做的确在逻辑上没有问题,...
  • tastelife
  • tastelife
  • 2012-03-08 16:47
  • 13177

Lambda中Func和Expression的区别

Lambda中Func和Expression的区别 static void TestExpression() { Func Func = () => 10; Expression> Expression = ()...
  • cadenzasolo
  • cadenzasolo
  • 2016-01-25 23:01
  • 1739

Lambda表达式详细总结

(一)输入参数 在Lambda表达式中,输入参数是Lambda运算符的左边部分。它包含参数的数量可以为0、1或者多个。只有当输入参数为1时,Lambda表达式左边的一对小括弧才可以省略。输入参数的数量大于或者等于2时,Lambda表达式左边的一对小括弧中的多个参数质检使用逗号(,)分割。 示例1 下...
  • wangboxian
  • wangboxian
  • 2014-12-23 14:17
  • 81456

C# Lambda表达式和查询表达式

  • 2014-12-17 11:31
  • 240KB
  • 下载

Lambda表达式详细总结

(一)输入参数 在Lambda表达式中,输入参数是Lambda运算符的左边部分。它包含参数的数量可以为0、1或者多个。只有当输入参数为1时,Lambda表达式左边的一对小括弧才可以省略。输入参数的数量大于或者等于2时,Lambda表达式左边的一对小括弧中的多个参数质检使用逗号(,)分割。 ...
  • wisgood
  • wisgood
  • 2016-06-01 22:20
  • 1397

lambda表达式更新数据库

前言 在Itoo中,遇到了要用lambda表达式来更新数据的需求,之前接触过用lambda表达式查询的代码,但是更新还是第一次遇到,在大神的帮助下,又学到一点。lambda表达式更新数据 ta_userrole t_UserRole = new ta_userrole();//定义要更新的那张表 ...
  • boniesunshine
  • boniesunshine
  • 2016-08-28 20:20
  • 1367

Lambda表达式详细总结

(一)输入参数 在Lambda表达式中,输入参数是Lambda运算符的左边部分。它包含参数的数量可以为0、1或者多个。只有当输入参数为1时,Lambda表达式左边的一对小括弧才可以省略。输入参数的数量大于或者等于2时,Lambda表达式左边的一对小括弧中的多个参数质检使用逗号(,)分割。 示例1...
  • mss359681091
  • mss359681091
  • 2016-09-13 11:12
  • 1587

lambda 表达式拼接

lambda 表达式拼接扩展方法
  • zhifeiya
  • zhifeiya
  • 2017-03-30 16:11
  • 1132
    个人资料
    • 访问:564727次
    • 积分:18489
    • 等级:
    • 排名:第599名
    • 原创:274篇
    • 转载:20篇
    • 译文:0篇
    • 评论:5683条
    和我交谈
    点击这里给我发消息 点击这里给我发消息
    时间你好?
    博客专栏
    最新评论