动态拼接表达式——Expression

我们在项目中会遇到以下查询需求吗?

比如需要查询出满足以下条件的会员:

 条件组一:30-40岁的男性会员

 条件组二:20-30岁的女性会员

 条件组三:60-80岁性别未知的会员

 条件组内是并且关系,但是条件组与组之间是或者关系。 

很多程序员脑袋可能会直接蹦出用where拼接条件组的想法,就如同下面图片所展示的方法 :

         生成的SQl语句:

 

根据生成的sql语句我们会发现直接使用Where拼接出来的sql语句是并且的关系,

原本我们想要的结果是组与组之间是或者的关系,但是现在变成了并且的关系,很显然不满足我们的查询需求。

想要达到我们的查询需求,我们得使用动态拼接条件的方法,通常我会使用Expression

        最终我们生成的sql语句为:

 从查询语句可以看出达到了我们的查询需求,组与组之间是或者的关系。 

 以下是举例代码:       

namespace MyTest
{
    /// <summary>
    /// 动态拼接表达式
    /// </summary>
    public class ExpressionTest : ApplicationService
    {
        public readonly IRepository<CrmMember, int> _memberRep;
        public ExpressionTest(IRepository<CrmMember, int> memberRep)
        {
            _memberRep = memberRep;

        }


        /// <summary>
        /// 使用动态拼接-Expression
        /// </summary>       
        public async Task Test()
        {
            #region 描述

            /*         
             *  条件组一:30-40岁的男性会员
             * 条件组二:20-30岁的女性会员
             *  条件组三:60-80岁性别未知的会员
             *  条件组内是并且关系,但是条件组与组之间是或者关系。 
            */
            #endregion

            #region 封装查询条件

            var param = new List<SearchMemberInputDto>
            {
                new SearchMemberInputDto { Sex = 1, AgeStart = 30, AgeEnd = 40 },// 30-40岁的男性
                new SearchMemberInputDto { Sex = 2, AgeStart = 20, AgeEnd = 30 }, // 20-30岁的女性
                new SearchMemberInputDto { Sex = 0, AgeStart = 20, AgeEnd = 30 }// 60-80岁性别未知
            };

            #endregion

            #region 动态拼接-Expression

            var members = (await _memberRep.GetAllAsync()).Where(a => a.GroupId == AbpSession.GroupId && a.IsDeleted == false);

            Expression<Func<CrmMember, bool>> expressions = s => false;

            foreach (var item in param)
            {
                expressions = expressions.Or(s => s.Sex == item.Sex && s.Age >= item.AgeStart && s.Age <= item.AgeEnd);
            }

            members = members.Where(expressions);

            var memberList = members.ToList();

            #endregion
        }


        /// <summary>
        /// 测试错误的方法
        /// </summary>       
        public async Task TestError()
        {
            #region 描述

            /*         
             *  条件组一:30-40岁的男性会员
             * 条件组二:20-30岁的女性会员
             *  条件组三:60-80岁性别未知的会员
             *  条件组内是并且关系,但是条件组与组之间是或者关系。 
             *
             注意:此方法是一个错误的写法 达不到查询需求
            */

            #endregion

            #region 封装查询条件

            var param = new List<SearchMemberInputDto>
            {
                new SearchMemberInputDto { Sex = 1, AgeStart = 30, AgeEnd = 40 },// 30-40岁的男性
                new SearchMemberInputDto { Sex = 2, AgeStart = 20, AgeEnd = 30 }, // 20-30岁的女性
                new SearchMemberInputDto { Sex = 0, AgeStart = 20, AgeEnd = 30 }// 60-80岁性别未知
            };

            #endregion            

            var members = (await _memberRep.GetAllAsync()).Where(a => a.GroupId == AbpSession.GroupId && a.IsDeleted == false);

            foreach (var item in param)
            {
                members = members.Where(s => s.Sex == item.Sex && s.Age >= item.AgeStart && s.Age <= item.AgeEnd);
            }

            var memberList = members.ToList();

        }

    }

    /// <summary>
    /// 条件
    /// </summary>
    public class SearchMemberInputDto
    {

        /// <summary>
        /// 性别
        ///0-未知; 1-男;2-女
        /// </summary>
        public int Sex { get; set; }

        /// <summary>
        /// 年龄-开始值
        /// </summary>
        public int AgeStart { get; set; }

        /// <summary>
        /// 年龄-结束值
        /// </summary>
        public int AgeEnd { get; set; }
    }

}
View Code

    这个是很简单的一种用法,我这里只做了简单的讲述,希望对大家有所帮助。

posted @ 2021-09-14 14:26  姚小丹  阅读(2307)  评论(7编辑  收藏  举报