lambda表达式转换sql
Posted 初冬十月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lambda表达式转换sql相关的知识,希望对你有一定的参考价值。
这是我在博客园的第一遍文章,想分享下lambda表达式转换sql。
喜欢EF的便捷与优雅,不喜欢生成的一坨sql。(PS:公司封装了一套访问数据库的方法,所以不确定是不是EF的问题,反正就是一坨密密麻麻的的sql,我有点点处女座小纠结,虽然我是天蝎座)
好了,废话少说。
1 public class LambdaToSqlHelper 2 { 3 /// <summary> 4 /// NodeType枚举 5 /// </summary> 6 private enum EnumNodeType 7 { 8 /// <summary> 9 /// 二元运算符 10 /// </summary> 11 [Description("二元运算符")] 12 BinaryOperator = 1, 13 14 /// <summary> 15 /// 一元运算符 16 /// </summary> 17 [Description("一元运算符")] 18 UndryOperator = 2, 19 20 /// <summary> 21 /// 常量表达式 22 /// </summary> 23 [Description("常量表达式")] 24 Constant = 3, 25 26 /// <summary> 27 /// 成员(变量) 28 /// </summary> 29 [Description("成员(变量)")] 30 MemberAccess = 4, 31 32 /// <summary> 33 /// 函数 34 /// </summary> 35 [Description("函数")] 36 Call = 5, 37 38 /// <summary> 39 /// 未知 40 /// </summary> 41 [Description("未知")] 42 Unknown = -99, 43 44 /// <summary> 45 /// 不支持 46 /// </summary> 47 [Description("不支持")] 48 NotSupported = -98 49 } 50 51 /// <summary> 52 /// 判断表达式类型 53 /// </summary> 54 /// <param name="exp">lambda表达式</param> 55 /// <returns></returns> 56 private static EnumNodeType CheckExpressionType(Expression exp) 57 { 58 switch (exp.NodeType) 59 { 60 case ExpressionType.AndAlso: 61 case ExpressionType.OrElse: 62 case ExpressionType.Equal: 63 case ExpressionType.GreaterThanOrEqual: 64 case ExpressionType.LessThanOrEqual: 65 case ExpressionType.GreaterThan: 66 case ExpressionType.LessThan: 67 case ExpressionType.NotEqual: 68 return EnumNodeType.BinaryOperator; 69 case ExpressionType.Constant: 70 return EnumNodeType.Constant; 71 case ExpressionType.MemberAccess: 72 return EnumNodeType.MemberAccess; 73 case ExpressionType.Call: 74 return EnumNodeType.Call; 75 case ExpressionType.Not: 76 case ExpressionType.Convert: 77 return EnumNodeType.UndryOperator; 78 default: 79 return EnumNodeType.Unknown; 80 } 81 } 82 83 /// <summary> 84 /// 表达式类型转换 85 /// </summary> 86 /// <param name="type"></param> 87 /// <returns></returns> 88 private static string ExpressionTypeCast(ExpressionType type) 89 { 90 switch (type) 91 { 92 case ExpressionType.And: 93 case ExpressionType.AndAlso: 94 return " and "; 95 case ExpressionType.Equal: 96 return " = "; 97 case ExpressionType.GreaterThan: 98 return " > "; 99 case ExpressionType.GreaterThanOrEqual: 100 return " >= "; 101 case ExpressionType.LessThan: 102 return " < "; 103 case ExpressionType.LessThanOrEqual: 104 return " <= "; 105 case ExpressionType.NotEqual: 106 return " <> "; 107 case ExpressionType.Or: 108 case ExpressionType.OrElse: 109 return " or "; 110 case ExpressionType.Add: 111 case ExpressionType.AddChecked: 112 return " + "; 113 case ExpressionType.Subtract: 114 case ExpressionType.SubtractChecked: 115 return " - "; 116 case ExpressionType.Divide: 117 return " / "; 118 case ExpressionType.Multiply: 119 case ExpressionType.MultiplyChecked: 120 return " * "; 121 default: 122 return null; 123 } 124 } 125 126 private static string BinarExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel) 127 { 128 BinaryExpression be = exp as BinaryExpression; 129 Expression left = be.Left; 130 Expression right = be.Right; 131 ExpressionType type = be.NodeType; 132 string sb = "("; 133 //先处理左边 134 sb += ExpressionRouter(left, listSqlParaModel); 135 sb += ExpressionTypeCast(type); 136 //再处理右边 137 string sbTmp = ExpressionRouter(right, listSqlParaModel); 138 if (sbTmp == "null") 139 { 140 if (sb.EndsWith(" = ")) 141 sb = sb.Substring(0, sb.Length - 2) + " is null"; 142 else if (sb.EndsWith(" <> ")) 143 sb = sb.Substring(0, sb.Length - 2) + " is not null"; 144 } 145 else 146 sb += sbTmp; 147 return sb += ")"; 148 } 149 150 private static string ConstantExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel) 151 { 152 ConstantExpression ce = exp as ConstantExpression; 153 if (ce.Value == null) 154 { 155 return "null"; 156 } 157 else if (ce.Value is ValueType) 158 { 159 GetSqlParaModel(listSqlParaModel, GetValueType(ce.Value)); 160 return "@para" + listSqlParaModel.Count; 161 } 162 else if (ce.Value is string || ce.Value is DateTime || ce.Value is char) 163 { 164 GetSqlParaModel(listSqlParaModel, GetValueType(ce.Value)); 165 return "@para" + listSqlParaModel.Count; 166 } 167 return ""; 168 } 169 170 private static string LambdaExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel) 171 { 172 LambdaExpression le = exp as LambdaExpression; 173 return ExpressionRouter(le.Body, listSqlParaModel); 174 } 175 176 private static string MemberExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel) 177 { 178 if (!exp.ToString().StartsWith("value")) 179 { 180 MemberExpression me = exp as MemberExpression; 181 if (me.Member.Name == "Now") 182 { 183 GetSqlParaModel(listSqlParaModel, DateTime.Now); 184 return "@para" + listSqlParaModel.Count; 185 } 186 return me.Member.Name; 187 } 188 else 189 { 190 var result = Expression.Lambda(exp).Compile().DynamicInvoke(); 191 if (result == null) 192 { 193 return "null"; 194 } 195 else if (result is ValueType) 196 { 197 GetSqlParaModel(listSqlParaModel, GetValueType(result)); 198 return "@para" + listSqlParaModel.Count; 199 } 200 else if (result is string || result is DateTime || result is char) 201 { 202 GetSqlParaModel(listSqlParaModel, GetValueType(result)); 203 return "@para" + listSqlParaModel.Count; 204 } 205 else if (result is int[]) 206 { 207 var rl = result as int[]; 208 StringBuilder sbTmp = new StringBuilder(); 209 foreach (var r in rl) 210 { 211 GetSqlParaModel(listSqlParaModel, r.ToString().ToInt32()); 212 sbTmp.Append("@para" + listSqlParaModel.Count + ","); 213 } 214 return sbTmp.ToString().Substring(0, sbTmp.ToString().Length - 1); 215 } 216 else if (result is string[]) 217 { 218 var rl = result as string[]; 219 StringBuilder sbTmp = new StringBuilder(); 220 foreach (var r in rl) 221 { 222 GetSqlParaModel(listSqlParaModel, r.ToString()); 223 sbTmp.Append("@para" + listSqlParaModel.Count + ","); 224 } 225 return sbTmp.ToString().Substring(0, sbTmp.ToString().Length - 1); 226 } 227 } 228 return ""; 229 } 230 231 private static string MethodCallExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel) 232 { 233 MethodCallExpression mce = exp as MethodCallExpression; 234 if (mce.Method.Name == "Contains") 235 { 236 if (mce.Object == null) 237 { 238 return string.Format("{0} in ({1})", ExpressionRouter(mce.Arguments[1], listSqlParaModel), ExpressionRouter(mce.Arguments[0], listSqlParaModel)); 239 } 240 else 241 { 242 if (mce.Object.NodeType == ExpressionType.MemberAccess) 243 { 244 //w => w.name.Contains("1") 245 var _name = ExpressionRouter(mce.Object, listSqlParaModel); 246 var _value = ExpressionRouter(mce.Arguments[0], listSqlParaModel); 247 var index = _value.RetainNumber().ToInt32() - 1; 248 listSqlParaModel[index].value = "%{0}%".FormatWith(listSqlParaModel[index].value); 249 return string.Format("{0} like {1}", _name, _value); 250 } 251 } 252 } 253 else if (mce.Method.Name == "OrderBy") 254 { 255 return string.Format("{0} asc", ExpressionRouter(mce.Arguments[1], listSqlParaModel)); 256 } 257 else if (mce.Method.Name == "OrderByDescending") 258 { 259 return string.Format("{0} desc", ExpressionRouter(mce.Arguments[1], listSqlParaModel)); 260 } 261 else if (mce.Method.Name == "ThenBy") 262 { 263 return string.Format("{0},{1} asc", MethodCallExpressionProvider(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel)); 264 } 265 else if (mce.Method.Name == "ThenByDescending") 266 { 267 return string.Format("{0},{1} desc", MethodCallExpressionProvider(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel)); 268 } 269 else if (mce.Method.Name == "Like") 270 { 271 return string.Format("({0} like {1})", ExpressionRouter(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel).Replace("\'", "")); 272 } 273 else if (mce.Method.Name == "NotLike") 274 { 275 return string.Format("({0} not like \'%{1}%\')", ExpressionRouter(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel).Replace("\'", "")); 276 } 277 else if (mce.Method.Name == "In") 278 { 279 return string.Format("{0} in ({1})", ExpressionRouter(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel)); 280 } 281 else if (mce.Method.Name == "NotIn") 282 { 283 return string.Format("{0} not in ({1})", ExpressionRouter(mce.Arguments[0], listSqlParaModel), ExpressionRouter(mce.Arguments[1], listSqlParaModel)); 284 } 285 return ""; 286 } 287 288 private static string NewArrayExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel) 289 { 290 NewArrayExpression ae = exp as NewArrayExpression; 291 StringBuilder sbTmp = new StringBuilder(); 292 foreach (Expression ex in ae.Expressions) 293 { 294 sbTmp.Append(ExpressionRouter(ex, listSqlParaModel)); 295 sbTmp.Append(","); 296 } 297 return sbTmp.ToString(0, sbTmp.Length - 1); 298 } 299 300 private static string ParameterExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel) 301 { 302 ParameterExpression pe = exp as ParameterExpression; 303 return pe.Type.Name; 304 } 305 306 private static string UnaryExpressionProvider(Expression exp, List<SqlParaModel> listSqlParaModel) 307 将带有连接的 SQL 查询转换为 lambda 表达式