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;
            }
        }
时间: 2024-10-03 14:10:06

C# 构建动态Lambda表达式的相关文章

SqlDataReader生成动态Lambda表达式

上一扁使用动态lambda表达式来将DataTable转换成实体,比直接用反射快了不少.主要是首行转换的时候动态生成了委托. 后面的转换都是直接调用委托,省去了多次用反射带来的性能损失. 今天在对SqlServer返回的流对象 SqlDataReader 进行处理,也采用动态生成Lambda表达式的方式转换实体. 先上一版代码 1 using System; 2 using System.Collections.Generic; 3 using System.Data; 4 using Syst

c# ef 排序字段动态,构建动态Lambda和扩展方法OrderBy

1.动态构建排序 Lambda /// <summary> /// 获取排序Lambda(如果动态排序,类型不同会导致转换失败) /// </summary> /// <typeparam name="T">数据字段类型</typeparam> /// <typeparam name="Tkey">排序字段类型</typeparam> /// <param name="defau

java增量构建关于lambda表达式的问题

项目需要做java增量构建和部署.基本方案很简单. 构建:通过git diff拿到方法体变化的java类,绕过maven,直接使用同版本的javac编译出class文件. 部署:基于java-instrument技术,采用attach的方式对方法体变化的class进行retransform. 问题:  某些类在retransform的时候总是会报如下类似错误.有时是add a method, 有时是delete a method.我们都知道,"原生的jvm只支持方法体的修改,不支持增删方法,修改

C# 动态Lambda表达式

借助一个强大的Nuget 包可以很方便地解析执行Lambda表达式格式的字符串:System.Linq.Dynamic.Core github: https://github.com/StefH/System.Linq.Dynamic.Core // 匿名类 //匿名类var a = new { Age = 1, Name = "小姐姐" }; Type aType = a.GetType(); var dataParameter = Expression.Parameter(aTyp

动态生成C# Lambda表达式

转载:http://www.educity.cn/develop/1407905.html,并整理! 对于C# Lambda的理解我们在之前的文章中已经讲述过了,那么作为Delegate的进化使用,为了让代码简洁和优雅的呈现,C# Lambda表达式的使用功不可灭,那么依托外部条件如何动态构建C# Lambda表达式呢.下面让我们来具体的看看实施. 或许你会奇怪这个需求是如何产生的…… 首先,Lambda 在 DLinq 中承担了以往 T-SQL 的部分角色:其次,在数据库设计中,我们往往需要依

Lambda表达式树构建(上)

概述 Lambda是C#常用的语句,采用委托等方式,来封装真实的代码块.Lambda其实就是语法糖,是一个匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量.它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型,支持带有可绑定到委托或表达式树的输入参数的内联表达式.常用的方法有Where.Select.SelectMany.Aggregate等:语法结构SomeList.Where(p=>p.property==value),其中SomeList基础

动态Lambda表达式打印HelloWorld

最近在用C#与数据库打交道.开发过程中采用了ORM模型(以前是纯sql玩法,复杂的逻辑用存储过程做). 为了能通过配置文件动态地查询字段,也就是说需要能这样写: db.AsQuery<T>.Select("字段")//伪代码 通过多方查找终于找到了方案,那就是用动态Lambda表达式树(.net3.5以后的版本支持). 后来看别人写的ORM代码中,将C#代码转为SQL语句时出采用了表达式树,所以马上提起了学习兴趣. 先写着写一个hello world ,就是动态地拼出一个

EntityFramework动态多条件查询与Lambda表达式树

          在常规的信息系统中, 我们有需要动态多条件查询的情况, 例如UI上有多个选择项可供用户选择多条件查询数据. 那么在.net平台Entity Framework下, 我们用Lambda表达式树如何实现, 这里我们需要一个PredicateBuilder的UML类图: 实现的代码是这样的: /// <summary> /// Enables the efficient, dynamic composition of query predicates. /// </summ

Java 8 动态类型语言Lambda表达式实现原理分析

Java 8支持动态语言,看到了很酷的Lambda表达式,对一直以静态类型语言自居的Java,让人看到了Java虚拟机可以支持动态语言的目标. import java.util.function.Consumer; public class Lambda { public static void main(String[] args) { Consumer<String> c = s -> System.out.println(s); c.accept("hello lambd