• C# 构建动态Lambda表达式


    做CURD开发的过程中,通常都会需要GetList,然而查询条件是一个可能变化的需求,如何从容对应需求变化呢?

    首先,我们来设计一个套路,尝试以最小的工作量完成一次查询条件的需求变更

    1.UI收集查询数据

    2.UI将查询数据传递给Service

    3.Service从查询配置(数据库、JSON、XML)中匹配出查询条件,并赋予UI取得的值

    4.Service根据查询配置(已赋值)构建查询表达式。

    5.执行查询返回数据。

    大概流程如下图所示:

    下面上代码,希望有人能看懂 ><

    查询保存设置

        public interface IEntity
        {
            int Id { get; set; }
        }
        public class QueryCondition : IEntity
        {
            [Key]
            public int Id { get; set; }
            /// <summary>
            /// 条件分组:以此做为查询条件
            /// </summary>
            public string Group { get; set; }
            /// <summary>
            /// 字段名称
            /// </summary>
            public string FieldName { get; set; }
            public int CompareType { get; set; }
            public int CompareDataType { get; set; }
            public string Value { get; set; }
        }

    查询条件DTO模型

        /// <summary>
        /// 查询结构
        /// </summary>
        public class QueryConditionModel
        {
            public string FieldName { get; set; }
            public CompareType Type { get; set; }
            public CompareDataType DataType { get; set; }
            public string Value { get; set; }
        }
        public enum CompareType
        {
            Equal = 1,
            GreaterThan = 2,
            GreaterThanOrEqual = 3,
            LessThan = 4,
            LessThanOrEqual = 5,
            Include = 6,
        }
        public enum CompareDataType
        {
            Int = 1,
            String = 2,
            Double = 3,
            Decimal = 4,
            Float = 5,
            DateTime = 6
        }

    查询条件DTO转换配置

        public class QueryConditionProfile : Profile
        {
    
            [Obsolete("")]
            protected override void Configure()
            {
                CreateMap<QueryCondition, QueryConditionModel>()
                    .ForMember(p => p.Type, opt =>
                    {
                        opt.MapFrom(k => (CompareType)k.CompareType);
                    })
                    .ForMember(p => p.DataType, opt =>
                    {
                        opt.MapFrom(k => (CompareDataType)k.CompareDataType);
                    })
                    ;
            }
        }

    查询条件构建

        public class ServiceBase 
        {
            protected XXXDbContext Ctx;
            /// <summary>
            /// 动态构建Lambda查询表达式
            /// </summary>
            /// <param name="searchItems"></param>
            /// <returns></returns>
            protected Expression<Func<T, bool>> BuildExpression<T>(IList<QueryConditionModel> searchItems)
            {
                var where = PredicateExtensionses.True<T>();
                if (!searchItems.Any()) return @where;
                foreach (var subitem in searchItems)
                {
                    try
                    {
                        var field = subitem.FieldName;
                        var compare = subitem.Type;
                        var type = subitem.DataType;
                        var value = subitem.Value;
                        if (string.IsNullOrEmpty(field)) continue;                 
                        if (string.IsNullOrEmpty(value)) continue;
                        //构建Lambda表达式
                        var parameter = Expression.Parameter(typeof(T), "p");
                        Expression constant;
                        //表达式左侧 like: p.Name
                        var left = Expression.PropertyOrField(parameter, field);
                        //表达式右侧,比较值, like '张三'
                        var right = Expression.Constant(value);
                        //比较表达式
                        switch (compare)
                        {
                            case CompareType.GreaterThan:
                                constant = Expression.GreaterThan(left, right);
                                break;
                            case CompareType.GreaterThanOrEqual:
                                constant = Expression.GreaterThanOrEqual(left, right);
                                break;
                            case CompareType.LessThan:
                                constant = Expression.LessThan(left, right);
                                break;
                            case CompareType.LessThanOrEqual:
                                constant = Expression.LessThanOrEqual(left, right);
                                break;
                            case CompareType.Include:
                                //like 查询,需要调用外部int或string的Contains方法
                                var method = type == CompareDataType.Int
                                    ? typeof(int).GetMethod("Contains", new Type[] { typeof(int) })
                                    : typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
                                constant = Expression.Call(left, method, right);
                                break;
                            case CompareType.Equal:
                            default:
                                constant = Expression.Equal(left, right);
                                break;
                        }
                        var lambda = Expression.Lambda<Func<T, Boolean>>(constant, parameter);
                        @where = @where.And(lambda);
                    }
                    catch (Exception ex)
                    {
                        //OnMethodExecuted(JsonConvert.SerializeObject(searchItems), JsonConvert.SerializeObject(ex), "",
                            LogType.Error);
                    }
    
    
                }
                return @where;
            }
            protected Expression<Func<T, bool>> GenerateConditions<T>(Dictionary<string, string> conditions, string fieldGroup)
            {
                //read query condition define
                var fields = Ctx.QueryConditions.Where(p => p.Group == fieldGroup).ToList();
    
                //read value from client conditions
                foreach (var condition in conditions)
                {
                    SetValue(fields, condition.Key, condition.Value);
                }
                var businessCondigions = fields.Select(Mapper.Map<EntityFramework.QueryCondition, QueryConditionModel>).ToList();
                return BuildExpression<T>(businessCondigions);
    
            }
            private void SetValue(IList<EntityFramework.QueryCondition> conditions, string name, string value)
            {
                var field = conditions.FirstOrDefault(p => p.FieldName == name);
                if (field == null) return;
                field.Value = value;
            }
        }

    调用示例:

            public IList<CustomerListModel> GetList(Dictionary<string,string> conditions, Pager pager)
            {
                try
                {
                    var skip = (pager.PageIndex - 1) * pager.PageSize;
    
                    var where = GenerateConditions<EntityFramework.Customer>(conditions, "CustomerQueryModel");
                    var query = Ctx.Customers.Include("MemberCard").WhereIf<EntityFramework.Customer>(where, pager);
                    var list = query.Skip(skip).Take(pager.PageSize).ToList();
                    var ret = new List<CustomerListModel>();
                    foreach (var customer in list)
                    {
                        ret.Add(Mapper.Map<EntityFramework.Customer, CustomerListModel>(customer));
                    }
                    //OnMethodExecuted("GetList", "", "", LogType.Operate);
                    return ret;
                }
                catch (Exception ex)
                {
                    //OnErrorThrow(JsonConvert.SerializeObject(conditions), JsonConvert.SerializeObject(ex), ex.Message);
                    throw ex;
                }
            }
  • 相关阅读:
    numpy函数库中一些常用函数的记录
    python 中的tile函数,shape函数,sum函数
    数据挖掘十大经典算法(详解)
    逻辑回归
    17个新手常见Python运行时错误
    5.3.4 Hadoop序列化框架
    5.3.3 自定义writable和RawComparatorWritable
    Qt5.11.2 VS2015编译activemq发送程序 _ITERATOR_DEBUG_LEVEL错误和崩溃解决
    @ConfigurationProperties实现配置注入到实体类
    C++微信网页协议实现和应用
  • 原文地址:https://www.cnblogs.com/blackice/p/5798486.html
Copyright © 2020-2023  润新知