AnalyticExpression.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using System.Text;
  7. namespace Ant.ORM.ORMV20.Core
  8. {
  9. public class AnalyticExpression
  10. {
  11. /// <summary>
  12. /// 递归解析表达式路由计算
  13. /// </summary>
  14. /// <returns></returns>
  15. private string CreateSqlElements(Expression exp, ref MemberType type, bool isTure = true)
  16. {
  17. if (exp is LambdaExpression)
  18. {
  19. LambdaExpression lambda = exp as LambdaExpression;
  20. var expression = lambda.Body;
  21. MemberType EleType = MemberType.None;
  22. return CreateSqlElements(expression, ref EleType);
  23. }
  24. else if (exp is BinaryExpression)
  25. {
  26. var expression = exp as BinaryExpression;
  27. MemberType leftType = MemberType.None;
  28. MemberType rightType = MemberType.None;
  29. var leftIsDateTime = expression.Left.Type.ToString().Contains("System.DateTime");
  30. var rightIsDateTime = expression.Right.Type.ToString().Contains("System.DateTime");
  31. var left = CreateSqlElements(expression.Left, ref leftType);
  32. var right = CreateSqlElements(expression.Right, ref rightType);
  33. var oper = GetOperator(expression.NodeType);
  34. var isKeyOperValue = leftType == MemberType.Key && rightType == MemberType.Value;
  35. var isValueOperKey = rightType == MemberType.Key && leftType == MemberType.Value;
  36. #region 处理 null
  37. if (isKeyOperValue & (right == "null" || right == null) && oper.Trim() == "=")
  38. {
  39. var oldLeft = AddParas(ref left, right);
  40. return string.Format(" ({0} is null ) ", oldLeft);
  41. }
  42. else if (isKeyOperValue & (right == "null" || right == null) && oper.Trim() == "<>")
  43. {
  44. var oldLeft = AddParas(ref left, right);
  45. return string.Format(" ({0} is not null ) ", oldLeft);
  46. }
  47. else if (isValueOperKey & (left == "null" || left == null) && oper.Trim() == "=")
  48. {
  49. return string.Format(" ({0} is null ) ", right);
  50. }
  51. else if (isValueOperKey & (left == "null" || left == null) && oper.Trim() == "<>")
  52. {
  53. return string.Format(" ({0} is not null ) ", right);
  54. }
  55. #endregion
  56. else if (isKeyOperValue)
  57. {
  58. object parValue = null;
  59. if (leftIsDateTime && right != null && right.IsDate())
  60. {
  61. parValue = Convert.ToDateTime(right);
  62. }
  63. else
  64. {
  65. parValue = right;
  66. }
  67. var oldLeft = AddParas(ref left, parValue);
  68. return string.Format(" ({0} {1} @{2}) ", oldLeft, oper, left);
  69. }
  70. else if (isValueOperKey)
  71. {
  72. object parValue = null;
  73. if (rightIsDateTime && left != null && left.IsDate())
  74. {
  75. parValue = Convert.ToDateTime(left);
  76. }
  77. else
  78. {
  79. parValue = left;
  80. }
  81. var oldRight = AddParasReturnRight(parValue, ref right);
  82. return string.Format("( @{0} {1} {2} )", right, oper, oldRight);
  83. }
  84. else if (leftType == MemberType.Value && rightType == MemberType.Value)
  85. {
  86. return string.Format("( '{0}' {1} '{2}' )", left, oper, right);
  87. }
  88. else
  89. {
  90. return string.Format("( {0} {1} {2} )", left, oper, right);
  91. }
  92. }
  93. else if (exp is BlockExpression)
  94. {
  95. }
  96. else if (exp is ConditionalExpression)
  97. {
  98. }
  99. else if (exp is MethodCallExpression)
  100. {
  101. MethodCallExpression mce = (MethodCallExpression)exp;
  102. string methodName = mce.Method.Name;
  103. if (methodName == "Contains")
  104. {
  105. return Contains(methodName, mce, isTure);
  106. }
  107. else if (methodName == "StartsWith")
  108. {
  109. return StartsWith(methodName, mce, isTure);
  110. }
  111. else if (methodName == "EndsWith")
  112. {
  113. return EndWith(methodName, mce, isTure);
  114. }
  115. else if (methodName == "ToString")
  116. {
  117. type = MemberType.Value;
  118. return MethodToString(methodName, mce, ref type);
  119. }
  120. else
  121. {
  122. type = MemberType.Value;
  123. return MethodTo(methodName, mce, ref type);
  124. }
  125. }
  126. else if (exp is ConstantExpression)
  127. {
  128. type = MemberType.Value;
  129. ConstantExpression ce = ((ConstantExpression)exp);
  130. if (ce.Value == null)
  131. return "null";
  132. else
  133. {
  134. return ce.Value.ToString();
  135. }
  136. }
  137. else if (exp is MemberExpression)
  138. {
  139. MemberExpression me = ((MemberExpression)exp);
  140. if (me.Expression == null || me.Expression.NodeType.ToString() != "Parameter")
  141. {
  142. type = MemberType.Value;
  143. object dynInv = null;
  144. try
  145. {
  146. // var dynInv = Expression.Lambda(exp).Compile().DynamicInvoke();原始写法性能极慢,下面写法性能提高了几十倍
  147. // var dynInv= Expression.Lambda(me.Expression as ConstantExpression).Compile().DynamicInvoke();
  148. var conExp = me.Expression as ConstantExpression;
  149. if (conExp != null)
  150. {
  151. dynInv = (me.Member as System.Reflection.FieldInfo).GetValue((me.Expression as ConstantExpression).Value);
  152. }
  153. else
  154. {
  155. var memberInfos = new Stack<MemberInfo>();
  156. // "descend" toward's the root object reference:
  157. while (exp is MemberExpression)
  158. {
  159. var memberExpr = exp as MemberExpression;
  160. memberInfos.Push(memberExpr.Member);
  161. exp = memberExpr.Expression;
  162. }
  163. // fetch the root object reference:
  164. var constExpr = exp as ConstantExpression;
  165. var objReference = constExpr.Value;
  166. // "ascend" back whence we came from and resolve object references along the way:
  167. while (memberInfos.Count > 0) // or some other break condition
  168. {
  169. var mi = memberInfos.Pop();
  170. if (mi.MemberType == MemberTypes.Property)
  171. {
  172. objReference = objReference.GetType()
  173. .GetProperty(mi.Name)
  174. .GetValue(objReference, null);
  175. }
  176. else if (mi.MemberType == MemberTypes.Field)
  177. {
  178. objReference = objReference.GetType()
  179. .GetField(mi.Name)
  180. .GetValue(objReference);
  181. }
  182. }
  183. dynInv = objReference;
  184. }
  185. }
  186. catch (Exception ex)
  187. {
  188. if (me.ToString() == "DateTime.Now")
  189. {
  190. return DateTime.Now.ToString();
  191. }
  192. Check.Exception(true, "错误信息:{0} \r\n message:{1}", "拉姆达解析出错,参数可支持的函数有 Trim 、Contains 、ObjToXXX、 Convert.ToXXX、Contains、StartsWith和StartsEnd。 ", ex.Message);
  193. }
  194. if (dynInv == null) return null;
  195. else
  196. return dynInv.ToString();
  197. }
  198. else
  199. {
  200. if (Type == ResolveExpressType.nT)
  201. {
  202. type = MemberType.Key;
  203. return exp.ToString();
  204. }
  205. string name = me.Member.Name;
  206. type = MemberType.Key;
  207. return name;
  208. }
  209. }
  210. else if (exp is UnaryExpression)
  211. {
  212. UnaryExpression ue = ((UnaryExpression)exp);
  213. var mex = ue.Operand;
  214. return CreateSqlElements(mex, ref type, false);
  215. }
  216. return null;
  217. }
  218. /// <summary>
  219. /// 拉姆达函数处理
  220. /// </summary>
  221. /// <param name="methodName"></param>
  222. /// <param name="mce"></param>
  223. /// <param name="type"></param>
  224. /// <returns></returns>
  225. private string MethodTo(string methodName, MethodCallExpression mce, ref MemberType type)
  226. {
  227. string value = string.Empty;
  228. if (mce.Arguments.IsValuable())
  229. {
  230. value = CreateSqlElements(mce.Arguments.FirstOrDefault(), ref type);
  231. }
  232. else
  233. {
  234. value = MethodToString(methodName, mce, ref type); ;
  235. }
  236. if (methodName == "ToDateTime" || methodName == "ObjToDate")
  237. {
  238. return Convert.ToDateTime(value).ToString();
  239. }
  240. else if (methodName.StartsWith("ToInt"))
  241. {
  242. return Convert.ToInt32(value).ToString();
  243. }
  244. else if (methodName.StartsWith("Trim"))
  245. {
  246. return (value.ObjToString()).Trim();
  247. }
  248. else if (methodName.StartsWith("ObjTo"))
  249. {
  250. return value;
  251. }
  252. return value;
  253. }
  254. /// <summary>
  255. /// 添加参数并返回右边值
  256. /// </summary>
  257. /// <param name="left"></param>
  258. /// <param name="right"></param>
  259. /// <returns></returns>
  260. private string AddParasReturnRight(object left, ref string right)
  261. {
  262. string oldRight = right;
  263. right = right + SameIndex;
  264. SameIndex++;
  265. if (Type != ResolveExpressType.oneT)
  266. {
  267. right = right.Replace(".", "_");
  268. }
  269. if (left == null)
  270. {
  271. this.Paras.Add(new SqlParameter("@" + right, DBNull.Value));
  272. }
  273. else
  274. {
  275. this.Paras.Add(new SqlParameter("@" + right, left));
  276. }
  277. return oldRight;
  278. }
  279. /// <summary>
  280. /// 拉姆达StartsWith函数处理
  281. /// </summary>
  282. /// <param name="methodName"></param>
  283. /// <param name="mce"></param>
  284. /// <param name="isTure"></param>
  285. /// <returns></returns>
  286. private string StartsWith(string methodName, MethodCallExpression mce, bool isTure)
  287. {
  288. MemberType leftType = MemberType.None;
  289. MemberType rightType = MemberType.None;
  290. var left = CreateSqlElements(mce.Object, ref leftType);
  291. var right = CreateSqlElements(mce.Arguments[0], ref rightType);
  292. var oldLeft = AddParas(ref left, right);
  293. return string.Format("({0} {1} LIKE @{2}+'%')", oldLeft, isTure == false ? " NOT " : null, left);
  294. }
  295. /// <summary>
  296. /// 拉姆达EndWith函数处理
  297. /// </summary>
  298. /// <param name="methodName"></param>
  299. /// <param name="mce"></param>
  300. /// <param name="isTure"></param>
  301. /// <returns></returns>
  302. private string EndWith(string methodName, MethodCallExpression mce, bool isTure)
  303. {
  304. MemberType leftType = MemberType.None;
  305. MemberType rightType = MemberType.None;
  306. var left = CreateSqlElements(mce.Object, ref leftType);
  307. var right = CreateSqlElements(mce.Arguments[0], ref rightType);
  308. var oldLeft = AddParas(ref left, right);
  309. return string.Format("({0} {1} LIKE '%'+@{2})", oldLeft, isTure == false ? " NOT " : null, left);
  310. }
  311. /// <summary>
  312. /// 拉姆达Contains函数处理
  313. /// </summary>
  314. /// <param name="methodName"></param>
  315. /// <param name="mce"></param>
  316. /// <param name="isTure"></param>
  317. /// <returns></returns>
  318. private string Contains(string methodName, MethodCallExpression mce, bool isTure)
  319. {
  320. MemberType leftType = MemberType.None;
  321. MemberType rightType = MemberType.None;
  322. var left = CreateSqlElements(mce.Object, ref leftType);
  323. var right = CreateSqlElements(mce.Arguments[0], ref rightType);
  324. var oldLeft = AddParas(ref left, right);
  325. return string.Format("({0} {1} LIKE '%'+@{2}+'%')", oldLeft, isTure == false ? " NOT " : null, left);
  326. }
  327. /// <summary>
  328. /// 根据条件生成对应的sql查询操作符
  329. /// </summary>
  330. /// <param name="expressiontype"></param>
  331. /// <returns></returns>
  332. private string GetOperator(ExpressionType expressiontype)
  333. {
  334. switch (expressiontype)
  335. {
  336. case ExpressionType.And:
  337. case ExpressionType.AndAlso:
  338. return " AND ";
  339. case ExpressionType.Equal:
  340. return " =";
  341. case ExpressionType.GreaterThan:
  342. return " >";
  343. case ExpressionType.GreaterThanOrEqual:
  344. return ">=";
  345. case ExpressionType.LessThan:
  346. return "<";
  347. case ExpressionType.LessThanOrEqual:
  348. return "<=";
  349. case ExpressionType.NotEqual:
  350. return "<>";
  351. case ExpressionType.Or:
  352. case ExpressionType.OrElse:
  353. return " OR ";
  354. case ExpressionType.Add:
  355. case ExpressionType.AddChecked:
  356. return "+";
  357. case ExpressionType.Subtract:
  358. case ExpressionType.SubtractChecked:
  359. return "-";
  360. case ExpressionType.Divide:
  361. return "/";
  362. case ExpressionType.Multiply:
  363. case ExpressionType.MultiplyChecked:
  364. return "*";
  365. default:
  366. throw new SqlSugarException(string.Format("拉姆达解析出错:不支持{0}此种运算符查找!" + expressiontype));
  367. }
  368. }
  369. /// <summary>
  370. /// 拉姆达成员类型
  371. /// </summary>
  372. public enum MemberType
  373. {
  374. None = 0,
  375. Key = 1,
  376. Value = 2
  377. }
  378. }
  379. }