You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

529 lines
18 KiB

2 years ago
  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. public abstract class QueryBuilder : IDMLBuilder
  10. {
  11. protected QueryBuilder()
  12. {
  13. this.Parameters = new List<SugarParameter>();
  14. }
  15. #region Private Fileds
  16. protected List<JoinQueryInfo> _JoinQueryInfos;
  17. protected Dictionary<string, string> _EasyJoinInfos;
  18. private List<string> _WhereInfos;
  19. private string _HavingInfos;
  20. protected string _TableNameString;
  21. #endregion Private Fileds
  22. #region Service object
  23. public StringBuilder sql { get; set; }
  24. public SqlSugarClient Context { get; set; }
  25. public ILambdaExpressions LambdaExpressions { get; set; }
  26. public ISqlBuilder Builder { get; set; }
  27. #endregion Service object
  28. #region Splicing basic
  29. public bool IsCount { get; set; }
  30. public int? Skip { get; set; }
  31. public int ExternalPageIndex { get; set; }
  32. public int ExternalPageSize { get; set; }
  33. public int? Take { get; set; }
  34. public string OrderByValue { get; set; }
  35. public object SelectValue { get; set; }
  36. public string SelectCacheKey { get; set; }
  37. public string EntityName { get; set; }
  38. public Type EntityType { get; set; }
  39. public string TableWithString { get; set; }
  40. public string GroupByValue { get; set; }
  41. public string PartitionByValue { get; set; }
  42. public int WhereIndex { get; set; }
  43. public int JoinIndex { get; set; }
  44. public bool IsDisabledGobalFilter { get; set; }
  45. public virtual List<SugarParameter> Parameters { get; set; }
  46. public Dictionary<string, string> EasyJoinInfos
  47. {
  48. get
  49. {
  50. _EasyJoinInfos = UtilMethods.IsNullReturnNew(_EasyJoinInfos);
  51. return _EasyJoinInfos;
  52. }
  53. set { _EasyJoinInfos = value; }
  54. }
  55. public virtual List<JoinQueryInfo> JoinQueryInfos
  56. {
  57. get
  58. {
  59. _JoinQueryInfos = UtilMethods.IsNullReturnNew(_JoinQueryInfos);
  60. return _JoinQueryInfos;
  61. }
  62. set { _JoinQueryInfos = value; }
  63. }
  64. public virtual string TableShortName { get; set; }
  65. public virtual List<string> WhereInfos
  66. {
  67. get
  68. {
  69. _WhereInfos = UtilMethods.IsNullReturnNew(_WhereInfos);
  70. return _WhereInfos;
  71. }
  72. set { _WhereInfos = value; }
  73. }
  74. public virtual string HavingInfos
  75. {
  76. get
  77. {
  78. return _HavingInfos;
  79. }
  80. set
  81. {
  82. _HavingInfos = value;
  83. }
  84. }
  85. #endregion Splicing basic
  86. #region Lambada Type
  87. public ResolveExpressType SelectType
  88. {
  89. get
  90. {
  91. return this.IsSingle() ? ResolveExpressType.SelectSingle : ResolveExpressType.SelectMultiple;
  92. }
  93. }
  94. public ResolveExpressType WheretType
  95. {
  96. get
  97. {
  98. return this.IsSingle() ? ResolveExpressType.WhereSingle : ResolveExpressType.WhereMultiple;
  99. }
  100. }
  101. #endregion Lambada Type
  102. #region Sql Template
  103. public virtual string SqlTemplate
  104. {
  105. get
  106. {
  107. return "SELECT {0} FROM {1}{2}{3}{4} ";
  108. }
  109. }
  110. public virtual string JoinTemplate
  111. {
  112. get
  113. {
  114. return "{0}JOIN {1}{2}ON {3} ";
  115. }
  116. }
  117. public virtual string PageTempalte
  118. {
  119. get
  120. {
  121. return @"SELECT * FROM ({0}) T WHERE RowIndex BETWEEN {1} AND {2}";
  122. }
  123. }
  124. public virtual string ExternalPageTempalte
  125. {
  126. get
  127. {
  128. return @"SELECT * FROM ({0}) T WHERE RowIndex2 BETWEEN {1} AND {2}";
  129. }
  130. }
  131. public virtual string DefaultOrderByTemplate
  132. {
  133. get
  134. {
  135. return "ORDER BY " + this.Builder.SqlDateNow + " ";
  136. }
  137. }
  138. public virtual string OrderByTemplate
  139. {
  140. get
  141. {
  142. return "ORDER BY ";
  143. }
  144. }
  145. public virtual string GroupByTemplate
  146. {
  147. get
  148. {
  149. return "GROUP BY ";
  150. }
  151. }
  152. public virtual string PartitionByTemplate
  153. {
  154. get
  155. {
  156. return "PARTITION BY ";
  157. }
  158. }
  159. public virtual string MaxTemplate
  160. {
  161. get
  162. {
  163. return "MAX({0})";
  164. }
  165. }
  166. public virtual string MinTemplate
  167. {
  168. get
  169. {
  170. return "MIN({0})";
  171. }
  172. }
  173. public virtual string SumTemplate
  174. {
  175. get
  176. {
  177. return "SUM({0})";
  178. }
  179. }
  180. public virtual string AvgTemplate
  181. {
  182. get
  183. {
  184. return "AVG({0})";
  185. }
  186. }
  187. public virtual string InTemplate
  188. {
  189. get
  190. {
  191. return "{0} IN ({1}) ";
  192. }
  193. }
  194. #endregion Sql Template
  195. #region Common Methods
  196. public virtual bool IsSingle()
  197. {
  198. var isSingle = Builder.QueryBuilder.JoinQueryInfos.IsNullOrEmpty() && !EasyJoinInfos.Any();
  199. return isSingle;
  200. }
  201. public virtual ExpressionResult GetExpressionValue(Expression expression, ResolveExpressType resolveType)
  202. {
  203. var resolveExpress = this.LambdaExpressions;
  204. if (resolveType.IsIn(ResolveExpressType.FieldSingle, ResolveExpressType.FieldMultiple, ResolveExpressType.SelectSingle, ResolveExpressType.SelectMultiple) && (expression is LambdaExpression) && (expression as LambdaExpression).Body is BinaryExpression)
  205. {
  206. resolveType = resolveType.IsIn(ResolveExpressType.SelectSingle, ResolveExpressType.FieldSingle) ? ResolveExpressType.WhereSingle : ResolveExpressType.WhereMultiple;
  207. }
  208. this.LambdaExpressions.Clear();
  209. resolveExpress.JoinQueryInfos = Builder.QueryBuilder.JoinQueryInfos;
  210. resolveExpress.IsSingle = IsSingle();
  211. resolveExpress.MappingColumns = Context.MappingColumns;
  212. resolveExpress.MappingTables = Context.MappingTables;
  213. resolveExpress.IgnoreComumnList = Context.IgnoreColumns;
  214. resolveExpress.SqlFuncServices = Context.CurrentConnectionConfig.ConfigureExternalServices?.SqlFuncServices;
  215. resolveExpress.InitMappingInfo = this.Context.InitMppingInfo;
  216. resolveExpress.RefreshMapping = () =>
  217. {
  218. resolveExpress.MappingColumns = Context.MappingColumns;
  219. resolveExpress.MappingTables = Context.MappingTables;
  220. resolveExpress.IgnoreComumnList = Context.IgnoreColumns;
  221. resolveExpress.SqlFuncServices = Context.CurrentConnectionConfig.ConfigureExternalServices?.SqlFuncServices;
  222. };
  223. resolveExpress.Resolve(expression, resolveType);
  224. this.Parameters.AddRange(resolveExpress.Parameters);
  225. var result = resolveExpress.Result;
  226. var isSingleTableHasSubquery = IsSingle() && resolveExpress.SingleTableNameSubqueryShortName.HasValue();
  227. if (isSingleTableHasSubquery)
  228. {
  229. Check.Exception(!string.IsNullOrEmpty(this.TableShortName) && resolveExpress.SingleTableNameSubqueryShortName != this.TableShortName, "{0} and {1} need same name");
  230. this.TableShortName = resolveExpress.SingleTableNameSubqueryShortName;
  231. }
  232. return result;
  233. }
  234. public virtual string ToSqlString()
  235. {
  236. var oldOrderBy = this.OrderByValue;
  237. var externalOrderBy = oldOrderBy;
  238. var isIgnoreOrderBy = this.IsCount && this.PartitionByValue.IsNullOrEmpty();
  239. AppendFilter();
  240. sql = new StringBuilder();
  241. if (this.OrderByValue == null && (Skip != null || Take != null)) this.OrderByValue = " ORDER BY GetDate() ";
  242. if (this.PartitionByValue.HasValue())
  243. {
  244. this.OrderByValue = this.PartitionByValue + this.OrderByValue;
  245. }
  246. var isRowNumber = Skip != null || Take != null;
  247. var rowNumberString = string.Format(",ROW_NUMBER() OVER({0}) AS RowIndex ", GetOrderByString);
  248. var groupByValue = GetGroupByString + HavingInfos;
  249. var orderByValue = (!isRowNumber && this.OrderByValue.HasValue()) ? GetOrderByString : null;
  250. if (isIgnoreOrderBy) { orderByValue = null; }
  251. sql.AppendFormat(SqlTemplate, GetSelectValue, GetTableNameString, GetWhereValueString, groupByValue, orderByValue);
  252. sql.Replace(UtilConstants.ReplaceKey, isRowNumber ? (isIgnoreOrderBy ? null : rowNumberString) : null);
  253. if (isIgnoreOrderBy) { this.OrderByValue = oldOrderBy; return sql.ToString(); }
  254. var result = ToPageSql(sql.ToString(), this.Take, this.Skip);
  255. if (ExternalPageIndex > 0)
  256. {
  257. if (externalOrderBy.IsNullOrEmpty())
  258. {
  259. externalOrderBy = " ORDER BY GetDate() ";
  260. }
  261. result = string.Format("SELECT *,ROW_NUMBER() OVER({0}) AS RowIndex2 FROM ({1}) ExternalTable ", GetExternalOrderBy(externalOrderBy), result);
  262. result = ToPageSql2(result, ExternalPageIndex, ExternalPageSize, true);
  263. }
  264. this.OrderByValue = oldOrderBy;
  265. return result;
  266. }
  267. public virtual void AppendFilter()
  268. {
  269. if (!IsDisabledGobalFilter && this.Context.QueryFilter.GeFilterList.HasValue())
  270. {
  271. var gobalFilterList = this.Context.QueryFilter.GeFilterList.Where(it => it.FilterName.IsNullOrEmpty()).ToList();
  272. foreach (var item in gobalFilterList.Where(it => it.IsJoinQuery == !IsSingle()))
  273. {
  274. var filterResult = item.FilterValue(this.Context);
  275. WhereInfos.Add(this.Builder.AppendWhereOrAnd(this.WhereInfos.IsNullOrEmpty(), filterResult.Sql));
  276. var filterParamters = this.Context.Ado.GetParameters(filterResult.Parameters);
  277. if (filterParamters.HasValue())
  278. {
  279. this.Parameters.AddRange(filterParamters);
  280. }
  281. }
  282. }
  283. }
  284. public virtual string GetExternalOrderBy(string externalOrderBy)
  285. {
  286. return Regex.Replace(externalOrderBy, @"\[\w+\]\.", "");
  287. }
  288. public virtual string ToCountSql(string sql)
  289. {
  290. return string.Format(" SELECT COUNT(1) FROM ({0}) CountTable ", sql);
  291. }
  292. public virtual string ToPageSql(string sql, int? take, int? skip, bool isExternal = false)
  293. {
  294. var temp = isExternal ? ExternalPageTempalte : PageTempalte;
  295. if (skip != null && take == null)
  296. {
  297. return string.Format(temp, sql.ToString(), skip.ObjToInt() + 1, long.MaxValue);
  298. }
  299. else if (skip == null && take != null)
  300. {
  301. return string.Format(temp, sql.ToString(), 1, take.ObjToInt());
  302. }
  303. else if (skip != null && take != null)
  304. {
  305. return string.Format(temp, sql.ToString(), skip.ObjToInt() + 1, skip.ObjToInt() + take.ObjToInt());
  306. }
  307. else
  308. {
  309. return sql.ToString();
  310. }
  311. }
  312. public virtual string ToPageSql2(string sql, int? pageIndex, int? pageSize, bool isExternal = false)
  313. {
  314. var temp = isExternal ? ExternalPageTempalte : PageTempalte;
  315. return string.Format(temp, sql.ToString(), (pageIndex - 1) * pageSize + 1, pageIndex * pageSize);
  316. }
  317. public virtual string ToJoinString(JoinQueryInfo joinInfo)
  318. {
  319. return string.Format(
  320. this.JoinTemplate,
  321. joinInfo.JoinType.ToString() + UtilConstants.Space,
  322. Builder.GetTranslationTableName(joinInfo.TableName) + UtilConstants.Space,
  323. joinInfo.ShortName + UtilConstants.Space + TableWithString,
  324. joinInfo.JoinWhere);
  325. }
  326. public virtual void Clear()
  327. {
  328. this.Skip = 0;
  329. this.Take = 0;
  330. this.sql = null;
  331. this.WhereIndex = 0;
  332. this.Parameters = null;
  333. this.GroupByValue = null;
  334. this._TableNameString = null;
  335. this.WhereInfos = null;
  336. this.JoinQueryInfos = null;
  337. }
  338. public virtual bool IsComplexModel(string sql)
  339. {
  340. return Regex.IsMatch(sql, @"AS \[\w+\.\w+\]");
  341. }
  342. #endregion Common Methods
  343. #region Get SQL Partial
  344. public virtual string GetSelectValue
  345. {
  346. get
  347. {
  348. var result = string.Empty;
  349. result = this.SelectValue == null || this.SelectValue is string ? GetSelectValueByString() : GetSelectValueByExpression();
  350. if (this.SelectType == ResolveExpressType.SelectMultiple)
  351. {
  352. this.SelectCacheKey = this.SelectCacheKey + string.Join("-", this._JoinQueryInfos.Select(it => it.TableName));
  353. }
  354. return result;
  355. }
  356. }
  357. public virtual string GetSelectValueByExpression()
  358. {
  359. var expression = this.SelectValue as Expression;
  360. var result = GetExpressionValue(expression, this.SelectType).GetResultString();
  361. this.SelectCacheKey = result;
  362. return result;
  363. }
  364. public virtual string GetSelectValueByString()
  365. {
  366. string result;
  367. if (this.SelectValue.IsNullOrEmpty())
  368. {
  369. string pre = null;
  370. if (this.JoinQueryInfos.HasValue() && this.JoinQueryInfos.Any(it => TableShortName.HasValue()))
  371. {
  372. pre = Builder.GetTranslationColumnName(TableShortName) + ".";
  373. }
  374. result = string.Join(",", this.Context.EntityMaintenance.GetEntityInfo(this.EntityType).Columns.Where(it => !it.IsIgnore).Select(it => pre + Builder.GetTranslationColumnName(it.EntityName, it.PropertyName)));
  375. }
  376. else
  377. {
  378. result = this.SelectValue.ObjToString();
  379. this.SelectCacheKey = result;
  380. }
  381. if (result.IsNullOrEmpty())
  382. {
  383. result = "*";
  384. }
  385. return result;
  386. }
  387. public virtual string GetWhereValueString
  388. {
  389. get
  390. {
  391. if (this.WhereInfos == null) return null;
  392. else
  393. {
  394. return string.Join(UtilConstants.Space, this.WhereInfos);
  395. }
  396. }
  397. }
  398. public virtual string GetJoinValueString
  399. {
  400. get
  401. {
  402. if (this.JoinQueryInfos.IsNullOrEmpty()) return null;
  403. else
  404. {
  405. return string.Join(UtilConstants.Space, this.JoinQueryInfos.Select(it => this.ToJoinString(it)));
  406. }
  407. }
  408. }
  409. public virtual string GetTableNameString
  410. {
  411. get
  412. {
  413. var result = Builder.GetTranslationTableName(EntityName);
  414. result += UtilConstants.Space;
  415. if (this.TableShortName.HasValue())
  416. {
  417. result += (TableShortName + UtilConstants.Space);
  418. }
  419. if (this.TableWithString.HasValue() && this.TableWithString != SqlWith.Null)
  420. {
  421. result += TableWithString + UtilConstants.Space;
  422. }
  423. if (!this.IsSingle())
  424. {
  425. result += GetJoinValueString + UtilConstants.Space;
  426. }
  427. if (this.EasyJoinInfos.IsValuable())
  428. {
  429. if (this.TableWithString.HasValue() && this.TableWithString != SqlWith.Null)
  430. {
  431. result += "," + string.Join(",", this.EasyJoinInfos.Select(it => string.Format("{0} {1} {2} ", GetTableName(it.Value), it.Key, TableWithString)));
  432. }
  433. else
  434. {
  435. result += "," + string.Join(",", this.EasyJoinInfos.Select(it => string.Format("{0} {1} ", GetTableName(it.Value), it.Key)));
  436. }
  437. }
  438. return result;
  439. }
  440. }
  441. public virtual string GetOrderByString
  442. {
  443. get
  444. {
  445. if (this.OrderByValue == null) return null;
  446. if (IsCount && this.PartitionByValue.IsNullOrEmpty()) return null;
  447. else
  448. {
  449. return this.OrderByValue;
  450. }
  451. }
  452. }
  453. public virtual string GetGroupByString
  454. {
  455. get
  456. {
  457. if (this.GroupByValue == null) return null;
  458. if (this.GroupByValue.Last() != ' ')
  459. {
  460. return this.GroupByValue + UtilConstants.Space;
  461. }
  462. return this.GroupByValue;
  463. }
  464. }
  465. #endregion Get SQL Partial
  466. private string GetTableName(string entityName)
  467. {
  468. var result = this.Context.EntityMaintenance.GetTableName(entityName);
  469. return this.Builder.GetTranslationTableName(result);
  470. }
  471. }
  472. }