SysDatabaseService.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // 麻省理工学院许可证
  2. //
  3. // 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
  4. //
  5. // 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
  6. //
  7. // 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
  8. // 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
  9. namespace Admin.NET.Core.Service;
  10. /// <summary>
  11. /// 系统数据库管理服务
  12. /// </summary>
  13. [ApiDescriptionSettings(Order = 250)]
  14. public class SysDatabaseService : IDynamicApiController, ITransient
  15. {
  16. private readonly ISqlSugarClient _db;
  17. private readonly IViewEngine _viewEngine;
  18. private readonly CodeGenOptions _codeGenOptions;
  19. public SysDatabaseService(ISqlSugarClient db,
  20. IViewEngine viewEngine,
  21. IOptions<CodeGenOptions> codeGenOptions)
  22. {
  23. _db = db;
  24. _viewEngine = viewEngine;
  25. _codeGenOptions = codeGenOptions.Value;
  26. }
  27. /// <summary>
  28. /// 获取库列表
  29. /// </summary>
  30. /// <returns></returns>
  31. [DisplayName("获取库列表")]
  32. public List<dynamic> GetList()
  33. {
  34. return App.GetOptions<DbConnectionOptions>().ConnectionConfigs.Select(u => u.ConfigId).ToList();
  35. }
  36. /// <summary>
  37. /// 获取字段列表
  38. /// </summary>
  39. /// <param name="tableName">表名</param>
  40. /// <param name="configId">ConfigId</param>
  41. /// <returns></returns>
  42. [AllowAnonymous]
  43. [DisplayName("获取字段列表")]
  44. public List<DbColumnOutput> GetColumnList(string tableName, string configId = SqlSugarConst.MainConfigId)
  45. {
  46. var db = _db.AsTenant().GetConnectionScope(configId);
  47. if (string.IsNullOrWhiteSpace(tableName))
  48. return new List<DbColumnOutput>();
  49. return db.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt<List<DbColumnOutput>>();
  50. }
  51. /// <summary>
  52. /// 增加列
  53. /// </summary>
  54. /// <param name="input"></param>
  55. [ApiDescriptionSettings(Name = "AddColumn"), HttpPost]
  56. [DisplayName("增加列")]
  57. public void AddColumn(DbColumnInput input)
  58. {
  59. var column = new DbColumnInfo
  60. {
  61. ColumnDescription = input.ColumnDescription,
  62. DbColumnName = input.DbColumnName,
  63. IsIdentity = input.IsIdentity == 1,
  64. IsNullable = input.IsNullable == 1,
  65. IsPrimarykey = input.IsPrimarykey == 1,
  66. Length = input.Length,
  67. DecimalDigits = input.DecimalDigits,
  68. DataType = input.DataType
  69. };
  70. var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
  71. db.DbMaintenance.AddColumn(input.TableName, column);
  72. db.DbMaintenance.AddColumnRemark(input.DbColumnName, input.TableName, input.ColumnDescription);
  73. if (column.IsPrimarykey)
  74. db.DbMaintenance.AddPrimaryKey(input.TableName, input.DbColumnName);
  75. }
  76. /// <summary>
  77. /// 删除列
  78. /// </summary>
  79. /// <param name="input"></param>
  80. [ApiDescriptionSettings(Name = "DeleteColumn"), HttpPost]
  81. [DisplayName("删除列")]
  82. public void DeleteColumn(DeleteDbColumnInput input)
  83. {
  84. var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
  85. db.DbMaintenance.DropColumn(input.TableName, input.DbColumnName);
  86. }
  87. /// <summary>
  88. /// 编辑列
  89. /// </summary>
  90. /// <param name="input"></param>
  91. [ApiDescriptionSettings(Name = "UpdateColumn"), HttpPost]
  92. [DisplayName("编辑列")]
  93. public void UpdateColumn(UpdateDbColumnInput input)
  94. {
  95. var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
  96. db.DbMaintenance.RenameColumn(input.TableName, input.OldColumnName, input.ColumnName);
  97. if (db.DbMaintenance.IsAnyColumnRemark(input.ColumnName, input.TableName))
  98. db.DbMaintenance.DeleteColumnRemark(input.ColumnName, input.TableName);
  99. db.DbMaintenance.AddColumnRemark(input.ColumnName, input.TableName, string.IsNullOrWhiteSpace(input.Description) ? input.ColumnName : input.Description);
  100. }
  101. /// <summary>
  102. /// 获取表列表
  103. /// </summary>
  104. /// <param name="configId">ConfigId</param>
  105. /// <returns></returns>
  106. [DisplayName("获取表列表")]
  107. public List<DbTableInfo> GetTableList(string configId = SqlSugarConst.MainConfigId)
  108. {
  109. var db = _db.AsTenant().GetConnectionScope(configId);
  110. return db.DbMaintenance.GetTableInfoList(false);
  111. }
  112. /// <summary>
  113. /// 增加表
  114. /// </summary>
  115. /// <param name="input"></param>
  116. [ApiDescriptionSettings(Name = "AddTable"), HttpPost]
  117. [DisplayName("增加表")]
  118. public void AddTable(DbTableInput input)
  119. {
  120. var columns = new List<DbColumnInfo>();
  121. if (input.DbColumnInfoList == null || !input.DbColumnInfoList.Any())
  122. throw Oops.Oh(ErrorCodeEnum.db1000);
  123. if (input.DbColumnInfoList.GroupBy(q => q.DbColumnName).Any(q => q.Count() > 1))
  124. throw Oops.Oh(ErrorCodeEnum.db1002);
  125. var config = App.GetOptions<DbConnectionOptions>().ConnectionConfigs.FirstOrDefault(u => u.ConfigId == input.ConfigId);
  126. var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
  127. var typeBilder = db.DynamicBuilder().CreateClass(input.TableName, new SugarTable() { TableName = input.TableName, TableDescription = input.Description });
  128. input.DbColumnInfoList.ForEach(m =>
  129. {
  130. var dbColumnName = config.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(m.DbColumnName.Trim()) : m.DbColumnName.Trim();
  131. var isPrimarykey = columns.Any(m => m.IsPrimarykey);
  132. // 虚拟类都默认String,具体以列数据类型为准
  133. typeBilder.CreateProperty(dbColumnName, typeof(string), new SugarColumn()
  134. {
  135. IsPrimaryKey = isPrimarykey,
  136. IsIdentity = m.IsIdentity == 1,
  137. ColumnDataType = m.DataType,
  138. Length = m.Length,
  139. IsNullable = m.IsNullable == 1,
  140. DecimalDigits = m.DecimalDigits,
  141. ColumnDescription = m.ColumnDescription,
  142. });
  143. });
  144. db.CodeFirst.InitTables(typeBilder.BuilderType());
  145. }
  146. /// <summary>
  147. /// 删除表
  148. /// </summary>
  149. /// <param name="input"></param>
  150. [ApiDescriptionSettings(Name = "DeleteTable"), HttpPost]
  151. [DisplayName("删除表")]
  152. public void DeleteTable(DeleteDbTableInput input)
  153. {
  154. var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
  155. db.DbMaintenance.DropTable(input.TableName);
  156. }
  157. /// <summary>
  158. /// 编辑表
  159. /// </summary>
  160. /// <param name="input"></param>
  161. [ApiDescriptionSettings(Name = "UpdateTable"), HttpPost]
  162. [DisplayName("编辑表")]
  163. public void UpdateTable(UpdateDbTableInput input)
  164. {
  165. var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
  166. db.DbMaintenance.RenameTable(input.OldTableName, input.TableName);
  167. try
  168. {
  169. if (db.DbMaintenance.IsAnyTableRemark(input.TableName))
  170. db.DbMaintenance.DeleteTableRemark(input.TableName);
  171. }
  172. catch (NotSupportedException)
  173. {
  174. //Ignore 不支持该方法则不处理
  175. }
  176. db.DbMaintenance.AddTableRemark(input.TableName, input.Description);
  177. }
  178. /// <summary>
  179. /// 创建实体
  180. /// </summary>
  181. /// <param name="input"></param>
  182. [ApiDescriptionSettings(Name = "CreateEntity"), HttpPost]
  183. [DisplayName("创建实体")]
  184. public void CreateEntity(CreateEntityInput input)
  185. {
  186. var config = App.GetOptions<DbConnectionOptions>().ConnectionConfigs.FirstOrDefault(u => u.ConfigId == input.ConfigId);
  187. input.Position = string.IsNullOrWhiteSpace(input.Position) ? "Admin.NET.Application" : input.Position;
  188. input.EntityName = string.IsNullOrWhiteSpace(input.EntityName) ? (config.DbSettings.EnableUnderLine ? CodeGenUtil.CamelColumnName(input.TableName, null) : input.TableName) : input.EntityName;
  189. string[] dbColumnNames = Array.Empty<string>();
  190. // 允许创建没有基类的实体
  191. if (!string.IsNullOrWhiteSpace(input.BaseClassName))
  192. {
  193. _codeGenOptions.EntityBaseColumn.TryGetValue(input.BaseClassName, out dbColumnNames);
  194. if (dbColumnNames is null || dbColumnNames is { Length: 0 })
  195. throw Oops.Oh("基类配置文件不存在此类型");
  196. }
  197. var templatePath = GetEntityTemplatePath();
  198. var targetPath = GetEntityTargetPath(input);
  199. var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
  200. DbTableInfo dbTableInfo = db.DbMaintenance.GetTableInfoList(false).FirstOrDefault(m => m.Name == input.TableName || m.Name == input.TableName.ToLower()) ?? throw Oops.Oh(ErrorCodeEnum.db1001);
  201. List<DbColumnInfo> dbColumnInfos = db.DbMaintenance.GetColumnInfosByTableName(input.TableName, false);
  202. dbColumnInfos.ForEach(u =>
  203. {
  204. u.PropertyName = config.DbSettings.EnableUnderLine ? CodeGenUtil.CamelColumnName(u.DbColumnName, dbColumnNames) : u.DbColumnName; // 转下划线后的列名需要再转回来
  205. u.DataType = CodeGenUtil.ConvertDataType(u, config.DbType);
  206. });
  207. if (_codeGenOptions.BaseEntityNames.Contains(input.BaseClassName, StringComparer.OrdinalIgnoreCase))
  208. dbColumnInfos = dbColumnInfos.Where(c => !dbColumnNames.Contains(c.DbColumnName, StringComparer.OrdinalIgnoreCase)).ToList();
  209. var tContent = File.ReadAllText(templatePath);
  210. var tResult = _viewEngine.RunCompileFromCached(tContent, new
  211. {
  212. NameSpace = $"{input.Position}.Entity",
  213. input.TableName,
  214. input.EntityName,
  215. BaseClassName = string.IsNullOrWhiteSpace(input.BaseClassName) ? "" : $" : {input.BaseClassName}",
  216. input.ConfigId,
  217. dbTableInfo.Description,
  218. TableField = dbColumnInfos
  219. });
  220. File.WriteAllText(targetPath, tResult, Encoding.UTF8);
  221. }
  222. /// <summary>
  223. /// 获取实体模板文件路径
  224. /// </summary>
  225. /// <returns></returns>
  226. private static string GetEntityTemplatePath()
  227. {
  228. var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath, "Template");
  229. return Path.Combine(templatePath, "Entity.cs.vm");
  230. }
  231. /// <summary>
  232. /// 设置生成实体文件路径
  233. /// </summary>
  234. /// <param name="input"></param>
  235. /// <returns></returns>
  236. private static string GetEntityTargetPath(CreateEntityInput input)
  237. {
  238. var backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName, input.Position, "Entity");
  239. if (!Directory.Exists(backendPath))
  240. Directory.CreateDirectory(backendPath);
  241. return Path.Combine(backendPath, input.EntityName + ".cs");
  242. }
  243. }