依据前端返回参数,动态构建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; } }
2、构建等式运算符
public enum Comparison { Equal = 0, NoEqual = 1, GreaterThan = 2, GreaterThanOrEqual = 3, LessThan = 4, LessThanOrEqual = 5, Like = 6, LikeLeft = 7, LikeRight = 8, In = 9, }
3、构建表达式分组类
public class GroupQuery { public string LinkName { get; set; } public int Count { get; set; } public List<QueryItem> Entitys { get; set; } }
4、构建表达式运算符
public enum JoinType { AndAlso, OrElse, }
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; }
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 }, }; } }
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" });
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)); }
9、结果
{"Money":600.0,"Sex":"男","ID":50,"Name":"张三"}