1.准备
- 环境:Asp.Net MVC5 、EF6
- 前置知识:反射、使用过EF编写过Lambda表达式
2.基础类库
2.1该高级条件的类型
1 /// <summary> 2 /// 当前条件所属类型 3 /// </summary> 4 public enum Em_AS_ConditionType 5 { 6 /// <summary> 7 /// 并 8 /// </summary> 9 [Description("并")] 10 And = 0, 11 12 /// <summary> 13 /// 或 14 /// </summary> 15 [Description("或")] 16 Or = 1 17 }
2.2搜索条件
1 /// <summary> 2 /// 高级搜索条件 3 /// </summary> 4 public enum Em_AS_Condition 5 { 6 /// <summary> 7 /// 包含 8 /// </summary> 9 [Description("包含")] 10 Include = 0, 11 12 /// <summary> 13 /// 等于 14 /// </summary> 15 [Description("=")] 16 Equal = 1, 17 18 /// <summary> 19 /// 大于等于 20 /// </summary> 21 [Description(">=")] 22 GtEqual = 2, 23 24 /// <summary> 25 /// 大于 26 /// </summary> 27 [Description(">")] 28 Gt = 3, 29 30 /// <summary> 31 /// 小于等于 32 /// </summary> 33 [Description("<=")] 34 LtEqual = 4, 35 36 /// <summary> 37 /// 小于 38 /// </summary> 39 [Description("<")] 40 Lt = 5, 41 }
2.3前端传来的数据模型格式
/// <summary> /// 高级查询 /// </summary>public class QM_Adv { /// <summary> /// 属性名称 /// </summary>public string PropName { get; set; } /// <summary> /// 条件 /// </summary>public Em_AS_Condition Condition { get; set; } /// <summary> /// 关键字 /// </summary>public string Keyword { get; set; } /// <summary> /// 这组条件与其它条件的关系 /// </summary>public Em_AS_ConditionType ConditionType { get; set; } }
3.准备好基础类库,然后就可以编写表达式树生成Lambda的代码了
3.1.表达式的种类
- BinaryExpression
- MethodCallExpression
3.1.1:BinaryExpression: 生成的lambda如:
p=>p.Age==21
p=>p.Age<=21
p=>p.Age!=21
3.1.2:MethodCallExpression:生成的lambda如
p=>p.Name.Contains("陈")
3.2方法介绍
3.2.1:Expression.Constant(object value) 创建一个常数表达式,一般方在表达式的右边;也可同时放在表达式的两边组成一个恒为真、恒为假的表达式
3.2.2:Expression.Property(ParameterExpression pe, string propertyName) 访问字段或属性,一般放在表达式左边;生成的表示式就是上面中的p=>p.Age,p=>p.Name
3.2.3:Expression.Call(Expression instance,MethodInfo method,Expression[] arguments) 返回一个MethodCallExpression
3.2.4:Expression.Equal(Expression left, Expression right) 返回两边相等的BinaryExpression如:p=>p.Age==21
3.2.5:还有很多类似与Expression.Equal这个方法的,可查阅https://msdn.microsoft.com/zh-cn/library/system.linq.expressions.expression(v=vs.110).aspx
3.3 示例代码
3.3.1:类库
1 /// <summary> 2 /// 恒为真 3 /// </summary> 4 /// <returns>表达式</returns> 5 public static Expression EqualTrueCompare() 6 { 7 var type = typeof(string); 8 var pRef = Expression.Constant(true); 9 var constantReference = Expression.Constant(true); 10 var be = Expression.Equal(pRef, constantReference); 11 return be; 12 } 13 14 /// <summary> 15 /// 包含 16 /// </summary> 17 /// <typeparam name="TSource">数据类型</typeparam> 18 /// <param name="pe">左侧表达式参数</param> 19 /// <param name="property">属性</param> 20 /// <param name="value">值</param> 21 /// <returns>表达式</returns> 22 public static Expression IncludeCompare<TSource>(ParameterExpression pe, string property, object value) 23 { 24 try 25 { 26 var type = typeof(TSource); 27 object val = null; 28 Type dyType = TypeConvert.GetValue(type, property, value, out val); 29 if (val == null) return null; 30 var propertyReference = Expression.Property(pe, property); 31 var constantReference = Expression.Constant(val, dyType); 32 var be = Expression.Call(propertyReference, typeof(string).GetMethod("Contains"), constantReference); 33 return be; 34 } 35 catch (Exception e) 36 { 37 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e); 38 return null; 39 } 40 } 41 42 /// <summary> 43 /// 等于 44 /// </summary> 45 /// <typeparam name="TSource">数据类型</typeparam> 46 /// <param name="pe">左侧表达式参数</param> 47 /// <param name="property">属性</param> 48 /// <param name="value">值</param> 49 /// <returns>表达式</returns> 50 public static Expression EqualCompare<TSource>(ParameterExpression pe, string property, object value) 51 { 52 try 53 { 54 var type = typeof(TSource); 55 object val = null; 56 Type dyType = TypeConvert.GetValue(type, property, value, out val); 57 if (val == null) return null; 58 var propertyReference = Expression.Property(pe, property); 59 var constantReference = Expression.Constant(val, dyType); 60 BinaryExpression be = Expression.Equal(propertyReference, constantReference); 61 return be; 62 } 63 catch (Exception e) 64 { 65 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e); 66 return null; 67 } 68 } 69 70 /// <summary> 71 /// 大于等于 72 /// </summary> 73 /// <typeparam name="TSource">数据类型</typeparam> 74 /// <param name="pe">左侧表达式参数</param> 75 /// <param name="property">属性</param> 76 /// <param name="value">值</param> 77 /// <returns>表达式</returns> 78 public static Expression GtEqualCompare<TSource>(ParameterExpression pe, string property, object value) 79 { 80 try 81 { 82 var type = typeof(TSource); 83 object val = null; 84 Type dyType = TypeConvert.GetValue(type, property, value, out val); 85 if (val == null) return null; 86 var propertyReference = Expression.Property(pe, property); 87 var constantReference = Expression.Constant(val, dyType); 88 BinaryExpression be = Expression.GreaterThanOrEqual(propertyReference, constantReference); 89 return be; 90 } 91 catch (Exception e) 92 { 93 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e); 94 return null; 95 } 96 } 97 98 /// <summary> 99 /// 大于 100 /// </summary> 101 /// <typeparam name="TSource">数据类型</typeparam> 102 /// <param name="pe">左侧表达式参数</param> 103 /// <param name="property">属性</param> 104 /// <param name="value">值</param> 105 /// <returns>表达式</returns> 106 public static Expression GtCompare<TSource>(ParameterExpression pe, string property, object value) 107 { 108 try 109 { 110 var type = typeof(TSource); 111 object val = null; 112 Type dyType = TypeConvert.GetValue(type, property, value, out val); 113 if (val == null) return null; 114 var propertyReference = Expression.Property(pe, property); 115 var constantReference = Expression.Constant(val, dyType); 116 BinaryExpression be = Expression.GreaterThan(propertyReference, constantReference); 117 return be; 118 } 119 catch (Exception e) 120 { 121 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e); 122 return null; 123 } 124 } 125 126 /// <summary> 127 /// 小于等于 128 /// </summary> 129 /// <typeparam name="TSource">数据类型</typeparam> 130 /// <param name="pe">左侧表达式参数</param> 131 /// <param name="property">属性</param> 132 /// <param name="value">值</param> 133 /// <returns>表达式</returns> 134 public static Expression LtEqualCompare<TSource>(ParameterExpression pe, string property, object value) 135 { 136 try 137 { 138 var type = typeof(TSource); 139 object val = null; 140 Type dyType = TypeConvert.GetValue(type, property, value, out val); 141 if (val == null) return null; 142 var propertyReference = Expression.Property(pe, property); 143 var constantReference = Expression.Constant(val, dyType); 144 BinaryExpression be = Expression.LessThanOrEqual(propertyReference, constantReference); 145 return be; 146 } 147 catch (Exception e) 148 { 149 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e); 150 return null; 151 } 152 } 153 154 /// <summary> 155 /// 小于 156 /// </summary> 157 /// <typeparam name="TSource">数据类型</typeparam> 158 /// <param name="pe">左侧表达式参数</param> 159 /// <param name="property">属性</param> 160 /// <param name="value">值</param> 161 /// <returns>表达式</returns> 162 public static Expression LtCompare<TSource>(ParameterExpression pe, string property, object value) 163 { 164 try 165 { 166 var type = typeof(TSource); 167 object val = null; 168 Type dyType = TypeConvert.GetValue(type, property, value, out val); 169 if (val == null) return null; 170 var propertyReference = Expression.Property(pe, property); 171 var constantReference = Expression.Constant(val, dyType); 172 BinaryExpression be = Expression.LessThan(propertyReference, constantReference); 173 return be; 174 } 175 catch (Exception e) 176 { 177 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e); 178 return null; 179 } 180 }
3.3.2:TypeConvert.cs
1 /// <summary> 2 /// 根据实体类动态转换值类型,并输出转换后的值 3 /// </summary> 4 /// <param name="type">实体类型</param> 5 /// <param name="propName">属性名</param> 6 /// <param name="value">原始值</param> 7 /// <param name="oVal">输出值</param> 8 /// <returns>该属性对应的数据类型</returns> 9 public static Type GetValue(Type type, string propName, object value, out object oVal) 10 { 11 Type objType = null; 12 object objValue = null; 13 foreach (var pi in type.GetProperties()) 14 { 15 if (pi.Name == propName) 16 { 17 objType = pi.PropertyType; 18 string typeStr = string.Empty; 19 bool isNullType = IsNullableType(pi.PropertyType); 20 if (isNullType) 21 { 22 typeStr = pi.PropertyType.GetGenericArguments()[0].Name.ToLower(); 23 } 24 else 25 { 26 typeStr = pi.PropertyType.Name.ToLower(); 27 } 28 switch (typeStr) 29 { 30 case "string": 31 objValue = value + ""; 32 break; 33 case "datetime": 34 DateTime tempDateTime; 35 bool isDateTime = DateTime.TryParse(value + "", out tempDateTime); 36 if (isDateTime) 37 { 38 objValue = tempDateTime; 39 } 40 else 41 { 42 objValue = null; 43 } 44 break; 45 case "int16": 46 case "int32": 47 case "int64": 48 int tempint = 0; 49 bool isInt = int.TryParse(value + "", out tempint); 50 if (isInt) 51 { 52 objValue = tempint; 53 } 54 else 55 { 56 objValue = null; 57 } 58 break; 59 case "double": 60 double tempDouble = 0; 61 var tempStrDouble = value + ""; 62 bool isDouble = double.TryParse(tempStrDouble, out tempDouble); 63 if (isDouble) 64 { 65 objValue = tempDouble; 66 } 67 else 68 { 69 objValue = null; 70 } 71 break; 72 case "decimal": 73 decimal tempDecimal = 0; 74 var tempStr = value + ""; 75 bool isdecimal = decimal.TryParse(tempStr, out tempDecimal); 76 if (isdecimal) 77 { 78 objValue = tempDecimal; 79 } 80 else 81 { 82 objValue = null; 83 } 84 break; 85 default: 86 87 break; 88 } 89 } 90 } 91 oVal = objValue; 92 return objType; 93 } 94 95 /// <summary> 96 /// 判定是否为可空类型 97 /// </summary> 98 /// <param name="theType">类型</param> 99 /// <returns></returns> 100 public static bool IsNullableType(Type theType) 101 { 102 return (theType.IsGenericType && theType.GetGenericTypeDefinition() == typeof(Nullable<>)); 103 }
3.4:将多个查询条件转换成表达式树
1 /// <summary> 2 /// 将高级查询转换成对应的表达式树 3 /// </summary> 4 /// <typeparam name="TSource">类型</typeparam> 5 /// <param name="conditions">高级查询条件集合</param> 6 /// <returns>对象数据类型的表达式树</returns> 7 public static Expression<Func<TSource, bool>> ConvertToExpression<TSource>(this List<QM_Adv> conditions) 8 { 9 var type = typeof(TSource); 10 var pe = Expression.Parameter(type, "p"); 11 12 Expression exp = null; 13 if (conditions == null) 14 { 15 exp = ExpressionLib.EqualTrueCompare(); 16 return Expression.Lambda<Func<TSource, bool>>(exp, pe); 17 } 18 //并:生成交集的条件 19 conditions.Where(p => p.ConditionType == Em_AS_ConditionType.And).ToList().ForEach(p => 20 { 21 Expression temp = GetExpressionTemp<TSource>(p, pe); 22 if (exp == null) 23 { 24 if (temp != null) 25 { 26 exp = temp; 27 } 28 } 29 else 30 { 31 if (temp != null) 32 { 33 exp = Expression.AndAlso(exp, temp); 34 } 35 } 36 }); 37 38 //或:生成并集的条件 39 conditions.Where(p => p.ConditionType == Em_AS_ConditionType.Or).ToList().ForEach(p => 40 { 41 Expression temp = GetExpressionTemp<TSource>(p, pe); 42 if (exp == null) 43 { 44 if (temp != null) 45 { 46 exp = temp; 47 } 48 } 49 else 50 { 51 if (temp != null) 52 { 53 exp = Expression.Or(exp, temp); 54 } 55 } 56 }); 57 if (exp == null) 58 { 59 exp = ExpressionLib.EqualTrueCompare(); 60 } 61 62 return Expression.Lambda<Func<TSource, bool>>(exp, pe); 63 } 64 65 private static Expression GetExpressionTemp<TSource>(QM_Adv p, ParameterExpression pe) 66 { 67 Expression temp = null; 68 switch (p.Condition) 69 { 70 case Em_AS_Condition.Include: 71 temp = ExpressionLib.IncludeCompare<TSource>(pe, p.PropName, p.Keyword); 72 break; 73 case Em_AS_Condition.GtEqual: 74 temp = ExpressionLib.GtEqualCompare<TSource>(pe, p.PropName, p.Keyword); 75 break; 76 case Em_AS_Condition.Gt: 77 temp = ExpressionLib.GtCompare<TSource>(pe, p.PropName, p.Keyword); 78 break; 79 case Em_AS_Condition.LtEqual: 80 81 temp = ExpressionLib.LtEqualCompare<TSource>(pe, p.PropName, p.Keyword); 82 break; 83 case Em_AS_Condition.Lt: 84 temp = ExpressionLib.LtCompare<TSource>(pe, p.PropName, p.Keyword); 85 break; 86 case Em_AS_Condition.Equal: 87 temp = ExpressionLib.EqualCompare<TSource>(pe, p.PropName, p.Keyword); 88 break; 89 default: 90 break; 91 } 92 return temp; 93 }
4.1最后结语
这是我第一次写博客,能力有限,有不对的地方欢迎指出