SubResolve.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. namespace SqlSugar
  8. {
  9. ///<summary>
  10. /// ** description:Get subquery sql
  11. /// ** author:sunkaixuan
  12. /// ** date:2017/9/17
  13. /// ** email:610262374@qq.com
  14. /// </summary>
  15. public class SubResolve
  16. {
  17. List<MethodCallExpression> allMethods = new List<MethodCallExpression>();
  18. private ExpressionContext context = null;
  19. private string subKey = "$SubAs:";
  20. private bool hasWhere;
  21. private bool isXmlPath = false;
  22. public SubResolve(MethodCallExpression expression, ExpressionContext context, Expression oppsiteExpression)
  23. {
  24. this.context = context;
  25. var currentExpression = expression;
  26. allMethods.Add(currentExpression);
  27. if (context.IsSingle && oppsiteExpression != null && oppsiteExpression is MemberExpression)
  28. {
  29. var childExpression = (oppsiteExpression as MemberExpression).Expression;
  30. if (childExpression is ParameterExpression)
  31. this.context.SingleTableNameSubqueryShortName = (childExpression as ParameterExpression).Name;
  32. else {
  33. this.context.SingleTableNameSubqueryShortName = (context.Expression as LambdaExpression).Parameters.First().Name;
  34. }
  35. }
  36. else if (context.IsSingle&& ExpressionTool.GetMethodName(currentExpression) != "ToList")
  37. {
  38. if (context.Expression is LambdaExpression)
  39. {
  40. this.context.SingleTableNameSubqueryShortName = (context.Expression as LambdaExpression).Parameters.First().Name;
  41. }
  42. else if (context.Expression is MethodCallExpression)
  43. {
  44. var expArgs = ((context.Expression as MethodCallExpression).Object as MethodCallExpression).Arguments;
  45. if (expArgs != null && expArgs.Any())
  46. {
  47. var meExp = expArgs[0] as LambdaExpression;
  48. if (meExp != null)
  49. {
  50. var selfParameterName = meExp.Parameters.First().Name;
  51. if ((meExp.Body is BinaryExpression))
  52. {
  53. context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Left as MemberExpression)?.Expression as ParameterExpression)?.Name;
  54. }
  55. if (ExpressionTool.GetMethodName(context.Expression).IsContainsIn("ToList") && meExp.Parameters.Any(it => it.Name == selfParameterName))
  56. {
  57. if (meExp.Body is BinaryExpression)
  58. {
  59. context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Right as MemberExpression)?.Expression as ParameterExpression)?.Name;
  60. }
  61. }
  62. if (context.SingleTableNameSubqueryShortName == selfParameterName)
  63. {
  64. if (meExp.Body is BinaryExpression)
  65. {
  66. context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Right as MemberExpression)?.Expression as ParameterExpression)?.Name;
  67. }
  68. }
  69. }
  70. }
  71. }
  72. else if (context.Expression.GetType().Name == "MethodBinaryExpression")
  73. {
  74. var subExp = (context.Expression as BinaryExpression).Left is MethodCallExpression ? (context.Expression as BinaryExpression).Left : (context.Expression as BinaryExpression).Right;
  75. if (subExp is MethodCallExpression)
  76. {
  77. var meExp = ((subExp as MethodCallExpression).Object as MethodCallExpression).Arguments[0] as LambdaExpression;
  78. var selfParameterName = meExp.Parameters.First().Name;
  79. context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Left as MemberExpression).Expression as ParameterExpression).Name;
  80. if (context.SingleTableNameSubqueryShortName == selfParameterName)
  81. {
  82. context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Right as MemberExpression).Expression as ParameterExpression).Name;
  83. }
  84. }
  85. }
  86. else if (context.RootExpression != null && context.Expression.GetType().Name == "SimpleBinaryExpression")
  87. {
  88. var name = (this.context.RootExpression as LambdaExpression).Parameters[0].Name;
  89. context.SingleTableNameSubqueryShortName = name;
  90. }
  91. else if (context.Expression is BinaryExpression)
  92. {
  93. var subExp = (context.Expression as BinaryExpression).Left is MethodCallExpression ? (context.Expression as BinaryExpression).Left : (context.Expression as BinaryExpression).Right;
  94. if (subExp is MethodCallExpression)
  95. {
  96. var argus = ((subExp as MethodCallExpression).Object as MethodCallExpression).Arguments;
  97. if (argus.Count > 0)
  98. {
  99. var meExp = argus[0] as LambdaExpression;
  100. var selfParameterName = meExp.Parameters.First().Name;
  101. context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Left as MemberExpression)?.Expression as ParameterExpression)?.Name;
  102. if (context.SingleTableNameSubqueryShortName == selfParameterName)
  103. {
  104. context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Right as MemberExpression).Expression as ParameterExpression).Name;
  105. }
  106. }
  107. }
  108. }
  109. else if (context.Expression is MemberInitExpression memberInitExpression)
  110. {
  111. var getParameters = ExpressionTool.GetParameters(context.Expression).Select(it=>it.Name).Distinct().ToList();
  112. if (getParameters?.Count()>1)
  113. {
  114. context.SingleTableNameSubqueryShortName = getParameters.First();
  115. }
  116. }
  117. else
  118. {
  119. Check.ExceptionEasy( "I'm sorry I can't parse the current expression","不支持当前表达式");
  120. }
  121. }
  122. var subIndex = this.context.SubQueryIndex;
  123. while (currentExpression != null)
  124. {
  125. var addItem = currentExpression.Object as MethodCallExpression;
  126. if (addItem != null)
  127. allMethods.Add(addItem);
  128. if (subIndex==this.context.SubQueryIndex&&addItem !=null&&addItem.Arguments.HasValue()&&addItem.Arguments.Any(it=>it.ToString().Contains("Subqueryable()"))) {
  129. this.context.SubQueryIndex++;
  130. }
  131. currentExpression = addItem;
  132. }
  133. }
  134. public string GetSql()
  135. {
  136. List<string> subItems = GetSubItems();
  137. var sqlItems = subItems.Where(it => !it.StartsWith(subKey)).ToList();
  138. var asItems = subItems.Where(it => it.StartsWith(subKey)).ToList();
  139. if (asItems.Any())
  140. {
  141. GetSubAs(sqlItems, asItems);
  142. }
  143. if (this.context.CurrentShortName.HasValue())
  144. {
  145. GetShortName(sqlItems);
  146. }
  147. var sql = "";
  148. if (sqlItems.Count(it => IsJoin(it)) > 1)
  149. {
  150. var index = sqlItems.IndexOf(sqlItems.First(x=>IsJoin(x)));
  151. var joinitems = sqlItems.Where(it => IsJoin(it)).ToList();
  152. joinitems.Reverse();
  153. var items = sqlItems.Where(it => !IsJoin(it)).ToList();
  154. items.InsertRange(index, joinitems);
  155. sql = string.Join(UtilConstants.Space, items);
  156. }
  157. else
  158. {
  159. sql = string.Join(UtilConstants.Space, sqlItems);
  160. }
  161. if (isXmlPath)
  162. {
  163. var xmlPath = context.DbMehtods.GetForXmlPath();
  164. if (xmlPath.HasValue())
  165. {
  166. sql = sql + xmlPath;
  167. }
  168. }
  169. return this.context.DbMehtods.Pack(sql);
  170. }
  171. private static bool IsJoin(string it)
  172. {
  173. return it.StartsWith(" INNER JOIN") || it.StartsWith(" LEFT JOIN");
  174. }
  175. private void GetSubAs(List<string> sqlItems, List<string> asItems)
  176. {
  177. for (int i = 0; i < sqlItems.Count; i++)
  178. {
  179. if (sqlItems[i].StartsWith("FROM " + this.context.SqlTranslationLeft))
  180. {
  181. var asName = this.context.GetTranslationTableName(asItems.First().Replace(subKey, ""), false);
  182. var repKey = $"\\{this.context.SqlTranslationLeft}.+\\{this.context.SqlTranslationRight}";
  183. sqlItems[i] = Regex.Replace(sqlItems[i], repKey, asName);
  184. }
  185. }
  186. }
  187. private void GetShortName(List<string> sqlItems)
  188. {
  189. for (int i = 0; i < sqlItems.Count; i++)
  190. {
  191. if (sqlItems[i].StartsWith("FROM " + this.context.SqlTranslationLeft))
  192. {
  193. sqlItems[i] = sqlItems[i]+" "+this.context.CurrentShortName +" ";
  194. }
  195. }
  196. }
  197. private List<string> GetSubItems()
  198. {
  199. var isSubSubQuery = this.allMethods.Select(it => it.ToString()).Any(it => Regex.Matches(it, "Subquery").Count > 1);
  200. var isubList = this.allMethods.Select(exp =>
  201. {
  202. if (isSubSubQuery)
  203. {
  204. this.context.JoinIndex = 1;
  205. this.context.SubQueryIndex = 0;
  206. }
  207. var methodName = exp.Method.Name;
  208. var items = SubTools.SubItems(this.context);
  209. var item = items.First(s => s.Name == methodName);
  210. if (item is SubWhere && hasWhere == false)
  211. {
  212. hasWhere = true;
  213. }
  214. else if (item is SubWhere)
  215. {
  216. item = items.First(s => s is SubAnd);
  217. }
  218. if (item is SubWhereIF && hasWhere == false)
  219. {
  220. hasWhere = true;
  221. }
  222. else if (item is SubWhereIF)
  223. {
  224. item = items.First(s => s is SubAndIF);
  225. }
  226. else if (item is SubSelectStringJoin)
  227. {
  228. isXmlPath = true;
  229. }
  230. item.Context = this.context;
  231. item.Expression = exp;
  232. return item;
  233. }).ToList();
  234. SetOrderByIndex(isubList);
  235. isubList.Insert(0, new SubBegin());
  236. if (isubList.Any(it => it is SubSelect||it is SubFirst))
  237. {
  238. isubList.Add(new SubTop() { Context = this.context });
  239. }
  240. if (isubList.Any(it => it is SubAny || it is SubNotAny))
  241. {
  242. isubList.Add(new SubLeftBracket());
  243. isubList.Add(new SubRightBracket());
  244. isubList.Add(new SubSelectDefault());
  245. }
  246. var db = this.context?.SugarContext?.Context;
  247. if (db != null&& db?.CurrentConnectionConfig?.DbType == DbType.SqlServer)
  248. {
  249. if (db.CurrentConnectionConfig?.MoreSettings?.IsWithNoLockSubquery == true)
  250. {
  251. if (!isubList.Any(it => it is SubWithNolock))
  252. {
  253. isubList.Add(new SubWithNolock() { Context = this.context });
  254. }
  255. }
  256. }
  257. isubList = isubList.OrderBy(it => it.Sort).ToList();
  258. var isHasWhere = isubList.Where(it => it is SubWhere).Any();
  259. var isJoin = isubList.Any(it => it is SubInnerJoin || it is SubLeftJoin);
  260. if (isJoin)
  261. {
  262. this.context.JoinIndex++;
  263. }
  264. List<string> result = isubList.Select(it =>
  265. {
  266. it.HasWhere = isHasWhere;
  267. return it.GetValue(it.Expression);
  268. }).ToList();
  269. this.context.JoinIndex = 0;
  270. return result;
  271. }
  272. private static void SetOrderByIndex(List<ISubOperation> isubList)
  273. {
  274. var orderByIndex = 0;
  275. var orderByList = isubList.Where(it => it is SubOrderBy || it is SubOrderByDesc).ToList();
  276. if (orderByList.Count > 1)
  277. {
  278. orderByList.Reverse();
  279. foreach (var item in orderByList)
  280. {
  281. if (item is SubOrderBy)
  282. {
  283. (item as SubOrderBy).OrderIndex = orderByIndex;
  284. orderByIndex++;
  285. }
  286. else if (item is SubOrderByDesc)
  287. {
  288. (item as SubOrderByDesc).OrderIndex = orderByIndex;
  289. orderByIndex++;
  290. }
  291. }
  292. }
  293. }
  294. }
  295. }