依据前端返回参数,动态构建lambda表达式

1、构建前端返回类

/// <summary>
    /// 查询明细
    /// </summary>
    public class QueryItem
    {
        /// <summary>
        /// 查询项字段
        /// </summary>
        public String WhereName { get; set; }
        /// <summary>
        /// 查询项方法
        /// </summary>
        public Comparison Method { get; set; }
        /// <summary>
        ////// </summary>
        public object Value { get; set; }

        /// <summary>
        /// 连接标识 and 或者 or 检查上一位和下一位是否相同
        /// </summary>
        public string LinkName { get; set; }
        public QueryItem()
        {

        }
        /// <summary>
        /// 有参构造函数
        /// </summary>
        public QueryItem(String whereName, Comparison method, Object value, string linkName)
        {
            WhereName = whereName;
            Method = method;
            Value = value;
            LinkName = linkName;
        }
    }
View Code

2、构建等式运算符

    public enum Comparison
    {
        Equal = 0,
        NoEqual = 1,
        GreaterThan = 2,
        GreaterThanOrEqual = 3,
        LessThan = 4,
        LessThanOrEqual = 5,
        Like = 6,
        LikeLeft = 7,
        LikeRight = 8,
        In = 9,
    }
View Code

3、构建表达式分组类

 public class GroupQuery
    {
        public string LinkName { get; set; }

        public int Count { get; set; }

        public List<QueryItem> Entitys { get; set; }
    }
View Code

4、构建表达式运算符

public enum JoinType
    {
        AndAlso,
        OrElse,
    }
View Code

5、表达式组装方法

public static Expression<Func<T, bool>> BuildExpression<T>
            (List<QueryItem> queryItems)
        {
            if (queryItems == null || queryItems.Count == 0)
                throw new Exception("查询条件不可为空值!");
            // 声明参数
            ParameterExpression exp = Expression.Parameter(typeof(T), "t");
            // 进行分组排序
            var groupList = queryItems.GroupBy(t => t.LinkName)
                .Select(t => new GroupQuery{ LinkName = t.Key, Count = t.Count(), Entitys = t.ToList() })
                .OrderBy(m => m.Count).ToList();

            // 表达式数据集合  采用数据栈 先进先出的原则
            List<Expression?> expressions = new List<Expression?>(); 
            for (int i = groupList.Count - 1; i >= 0; i--)
            {
                var list = groupList[i];
                Expression? expression = GetExpressionNode<T>(list.Entitys, exp, list.Count > 1 ? JoinType.OrElse : JoinType.AndAlso);
                expressions.Add(expression);
            }

            Expression body = GetExpression(expressions);

            return Expression.Lambda<Func<T, bool>>(body, exp);
        }

        /// <summary>
        /// 组装表达式
        /// </summary>
        private static Expression GetExpression(List<Expression> expressions)
        {
            Expression exp = null;

            #region 第一步  获取右侧节点
            Expression right = expressions.First();
            #endregion

            #region 第二步  移除右侧节点 判断剩下的节点
            expressions.Remove(right);
            if(expressions.Count == 0)
            {
                return right;
            }else if(expressions.Count == 1)
            {
                exp = Expression.AndAlso(expressions[0],right);
            }
            else
            {
                Expression left = GetExpression(expressions);
                exp = Expression.AndAlso(left,right);
            }
            #endregion

            return exp;
        }

        /// <summary>
        /// 组装二叉树节点
        /// </summary>
        private static Expression? GetExpressionNode<T>(List<QueryItem> QueryItems,ParameterExpression exp, JoinType joinType)
        {
            Expression expression = null;
            var Querys = QueryItems;
            var last = Querys.Last();

            #region 第一步  取出最后一条作为右侧节点
            // 组装等式左侧
            Expression Node_right_left = Expression.Property(exp, typeof(T).GetProperty(last.WhereName));
            // 组装等式右侧
            Expression Node_right_right = GetExpressionValue(Node_right_left, last.Value);
            // 等式组装完毕
            Expression Node_right_Binary = GetBinaryExpression(Node_right_left, Node_right_right, last.Method);
            #endregion

            #region 第二步  移除最后一条 判断剩余的
            Querys.Remove(last);
            Expression Node_left_Binary = null;
           // 没有左侧节点
            if(Querys.Count == 0)
            {
                return Node_right_Binary;
            }
            // 此时只有一条  代表不用递归了 左侧节点就是当前数据
            else if (Querys.Count == 1)
            {
                var first = Querys.First();

                // 组装等式左侧
                Expression Node_left_left = Expression.Property(exp, typeof(T).GetProperty(first.WhereName));
                // 组装等式右侧
                Expression Node_left_right = GetExpressionValue(Node_left_left, first.Value);
                // 等式组装完毕
                Node_left_Binary = GetBinaryExpression(Node_left_left, Node_left_right, first.Method);
            }
            else
            {
                Node_left_Binary = GetExpressionNode<T>(Querys, exp, joinType);
            }

            #endregion

            #region 第三步  组装二叉树两侧节点
            if (joinType == JoinType.AndAlso)
            {
                expression = Expression.AndAlso(Node_left_Binary, Node_right_Binary);
            }
            else
            {
                expression = Expression.OrElse(Node_left_Binary, Node_right_Binary);
            }
            #endregion

            return expression;
        }

        /// <summary>
        /// 组装等式
        /// </summary>
        private static Expression GetBinaryExpression(Expression left,Expression right, Comparison comparison)
        {
            return comparison switch
            {
                Comparison.Equal => Expression.Equal(left,right),
                Comparison.NoEqual => Expression.NotEqual(left,right),
                Comparison.GreaterThan => Expression.GreaterThan(left,right),
                Comparison.GreaterThanOrEqual => Expression.GreaterThanOrEqual(left,right),
                Comparison.LessThan => Expression.LessThan(left,right),
                Comparison.LessThanOrEqual => Expression.LessThanOrEqual(left,right),
                Comparison.In => Expression.Call(left, typeof(String).GetMethod("Contains", new Type[] { typeof(String) }), right),
                Comparison.Like => Expression.Call(left, typeof(String).GetMethod("Contains", new Type[] { typeof(String) }), right),
                Comparison.LikeLeft => Expression.Call(left, typeof(String).GetMethod("EndsWith", new Type[] { typeof(String) }), right),
                Comparison.LikeRight => Expression.Call(left, typeof(String).GetMethod("StartsWith", new Type[] { typeof(String) }), right),
                _ => throw new Exception ("暂未支持")
            };
        }

        /// <summary>
        /// 获取等式右侧的表达式
        /// </summary>
        private static Expression GetExpressionValue(Expression left,object value)
        {
            Expression right = null;

            #region 处理日期时间

            if (left.Type.Equals(typeof(DateTime)))
            {
                right = Expression.Constant(DateTime.Parse(value.ToString()), typeof(DateTime));
            }
            else if (left.Type.Equals(typeof(Nullable<DateTime>)))
            {
                right = Expression.Constant(DateTime.Parse(value.ToString()), typeof(DateTime?));
            }

            #endregion

            #region 处理Guid

            else if (left.Type.Equals(typeof(Guid)))
            {
                right = Expression.Constant(Guid.Parse(value.ToString()), typeof(Guid));
            }
            else if (left.Type.Equals(typeof(Guid?)))
            {
                right = Expression.Constant(Guid.Parse(value.ToString()), typeof(Guid?));
            }

            #endregion

            #region 处理float

            else if (left.Type.Equals(typeof(float)))
            {
                right = Expression.Constant(float.Parse(value.ToString()), typeof(float));
            }
            else if (left.Type.Equals(typeof(float?)))
            {
                right = Expression.Constant(float.Parse(value.ToString()), typeof(float?));
            }

            #endregion

            #region 处理Double

            else if (left.Type.Equals(typeof(double)))
            {
                right = Expression.Constant(double.Parse(value.ToString()), typeof(double));
            }
            else if (left.Type.Equals(typeof(double?)))
            {
                right = Expression.Constant(double.Parse(value.ToString()), typeof(double?));
            }

            #endregion

            #region 处理int

            else if (left.Type.Equals(typeof(int)))
            {
                right = Expression.Constant(int.Parse(value.ToString()), typeof(int));
            }
            else if (left.Type.Equals(typeof(int?)))
            {
                right = Expression.Constant(int.Parse(value.ToString()), typeof(int?));
            }

            #endregion

            #region 处理字符串

            else
            {
                right = Expression.Constant(value.ToString(), typeof(String));
            }

            #endregion

            return right;
        }
View Code

6、构建测试数据

 public class Book
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public string Sex { get; set; }

        public double Money { get; set; }

        public static List<Book> GetBooks() {

            return new List<Book> {
                new Book { ID = 50 ,Name = "张三", Sex = "",Money = 600 },
                new Book { ID = 150 ,Name = "李四", Sex = "",Money = 1200 },
                new Book { ID = 100 ,Name = "王五", Sex = "",Money = 200 },
                new Book { ID = 10 ,Name = "马六", Sex = "",Money = 8000 },
                new Book { ID = 99 ,Name = "小明", Sex = "",Money = 1 },
            };
        }
    }
View Code

7、组建前端返回查询明细集合

List<QueryItem> queryItems = new List<QueryItem>();

queryItems.Add(new QueryItem { WhereName = "ID",Method = Comparison.GreaterThan, Value = 0 , LinkName = "ID1" });
queryItems.Add(new QueryItem { WhereName = "ID", Method = Comparison.LessThanOrEqual,Value = 50, LinkName = "ID2" });
queryItems.Add(new QueryItem { WhereName = "Sex", Method = Comparison.Equal, Value = "", LinkName = "ID" });
queryItems.Add(new QueryItem { WhereName = "Money", Method = Comparison.GreaterThan, Value = 100, LinkName = "ID" });
queryItems.Add(new QueryItem { WhereName = "Money", Method = Comparison.LessThan, Value = 500, LinkName = "ID" });
View Code

8、测试查看结果

var exp = ExpressionTest.BuildExpression<Book>(queryItems);

var data = Book.GetBooks().AsQueryable();

var book = data.Where(exp);

foreach (var item in book)
{
    Console.WriteLine(JsonConvert.SerializeObject(item));
}
View Code

9、结果

{"Money":600.0,"Sex":"","ID":50,"Name":"张三"}

 

posted @ 2022-11-21 23:28  苏瑾~  阅读(52)  评论(1编辑  收藏  举报