BuildSqlExtensions.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. using System.Collections.Generic;
  2. using System.Text;
  3. using System;
  4. using System.Linq;
  5. using System.Text.RegularExpressions;
  6. namespace JiaZhiQuan.Common.Utils.Extend {
  7. public static class BuildSqlExtensions {
  8. /// <summary>
  9. /// 生成更新sql
  10. /// </summary>
  11. /// <param name="source">数据</param>
  12. /// <param name="tableName">表名</param>
  13. /// <param name="uniqueFields">唯一字段,多个字段逗号隔开</param>
  14. /// <param name="cover">字段值为null时是否覆盖,默认覆盖</param>
  15. /// <returns></returns>
  16. /// <exception cref="Exception"></exception>
  17. public static string BuildBatchUpdatesql(this IEnumerable<object> source, string tableName,
  18. string uniqueFields, bool cover = true) {
  19. if (source.Count() == 0) return string.Empty;
  20. List<string> keyFields = uniqueFields?.Split(',').Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
  21. if (keyFields == null || keyFields.Count() == 0) throw new Exception("唯一字段列表不能为空");
  22. //考虑怎么写更优雅
  23. IEnumerable<IDictionary<string, object>> check = source.Where(x => x != null).Select(
  24. x => (IDictionary<string, object>)ExpandoUtils.ConvertToDynamic(x));
  25. foreach (var item in check) {
  26. foreach (var key in keyFields) {
  27. if (!item.ContainsKey(key)) throw new Exception("唯一字段不在数据字段中,不能创建更新sql");
  28. if (item[key] == null) throw new Exception("唯一字段对应的数据不能为空,不能创建更新sql");
  29. }
  30. }
  31. //根据唯一字段去重数据
  32. var data = check.Distinct(x => string.Join(",", keyFields.Select(y => x[y])));
  33. var fields = data.First().Keys;
  34. var cols = fields.Where(x => !keyFields.Contains(x));
  35. if (0 == cols.Count()) {
  36. return string.Empty;
  37. }
  38. StringBuilder sb = new StringBuilder("update ");
  39. sb.Append(tableName).Append(" t inner join ");
  40. sb.Append(BuildForeachStr(data, " union all ", t => {
  41. return BuildForeachStr(fields, ",",
  42. k => (null == t[k] ? "null" : "'" + EscapeSql(t[k]) + "'") + " " + k,
  43. "select ", null);
  44. }, "(", ")"));
  45. sb.Append(" a on ");
  46. sb.Append(BuildForeachStr(keyFields, " and ", t => $"t.{t}=a.{t}"));
  47. sb.Append(" set ");
  48. //是否覆盖
  49. if (cover) {
  50. sb.Append(BuildForeachStr(cols, ",", t => $"t.{t}=a.{t}"));
  51. } else {
  52. sb.Append(BuildForeachStr(cols, ",",
  53. t => $"t.{t}=case when a.{t} is null then t.{t} else a.{t} end"));
  54. }
  55. sb.Append(";select row_count();");
  56. return sb.ToString();
  57. }
  58. /// <summary>
  59. /// 生成插入sql,如果数据在库中存在,则去掉,并且会根据keyFields去重数据
  60. /// </summary>
  61. /// <param name="source">数据</param>
  62. /// <param name="tableName">表名</param>
  63. /// <param name="uniqueFields">唯一字段,多个字段逗号隔开</param>
  64. /// <returns></returns>
  65. /// <exception cref="Exception"></exception>
  66. public static string BuildBatchInsertsql(this IEnumerable<object> source, string tableName,
  67. string uniqueFields) {
  68. if (source.Count() == 0) return string.Empty;
  69. List<string> keyFields=uniqueFields?.Split(',').Where(x=>!string.IsNullOrWhiteSpace(x)).ToList();
  70. if (keyFields == null || keyFields.Count() == 0) throw new Exception("唯一字段列表不能为空");
  71. //考虑怎么写更优雅
  72. IEnumerable<IDictionary<string, object>> check = source.Where(x => x != null).Select(
  73. x => (IDictionary<string, object>)ExpandoUtils.ConvertToDynamic(x));
  74. foreach (var item in check) {
  75. foreach (var key in keyFields) {
  76. if (!item.ContainsKey(key)) throw new Exception("唯一字段不在数据字段中,不能创建插入sql");
  77. if (item[key] == null) throw new Exception("唯一字段对应的数据不能为空,不能创建插入sql");
  78. }
  79. }
  80. //根据唯一字段去重数据
  81. var data = check.Distinct(x => string.Join(",", keyFields.Select(y => x[y])));
  82. var fields = data.First().Keys;
  83. StringBuilder sb = new StringBuilder("insert into " + tableName);
  84. sb.Append(BuildForeachStr(fields, ",", open: "(", close: ")"));
  85. sb.Append(" select a.* from ").Append(BuildForeachStr(data, " union all ", t => {
  86. return BuildForeachStr(fields, ",",
  87. k => (null == t[k] ? "null" : "'" + EscapeSql(t[k]) + "'") + " " + k,
  88. "select ", null);
  89. }, "(", ")a "));
  90. sb.Append($" left join {tableName} t on ");
  91. sb.Append(BuildForeachStr(keyFields, " and ", t => $"t.{t}=a.{t} "));
  92. sb.Append($"where t.{keyFields.First()} is null ;select row_count();");
  93. return sb.ToString();
  94. }
  95. public static string BuildForeachStr<T>(this IEnumerable<T> list,
  96. string split, Func<T, string> getInfo = null, string open = null, string close = null) {
  97. if (list.Count() == 0) {
  98. return string.Empty;
  99. }
  100. StringBuilder sb = new StringBuilder(" ").Append(open ?? "");
  101. sb.Append(string.Join(split, list.Select(x => getInfo == null ? x.ToString() : getInfo(x))));
  102. sb.Append(close ?? "").Append(" ");
  103. return sb.ToString();
  104. }
  105. private static string EscapeSql(object value) {
  106. if (null == value) return null;
  107. if (value is DateTime time) return time.ToString("yyyy-MM-dd HH:mm:ss");
  108. else {
  109. return value.ToString().Replace(@"\", @"\\").Replace(@"'", @"\'");
  110. }
  111. }
  112. }
  113. }