DbHelper.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. using Microsoft.Extensions.DependencyModel;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Threading.Tasks;
  7. using FreeSql;
  8. using FreeSql.Aop;
  9. using FreeSql.DataAnnotations;
  10. using Yitter.IdGenerator;
  11. using ZhonTai.Admin.Core.Configs;
  12. using ZhonTai.Admin.Core.Entities;
  13. using ZhonTai.Admin.Core.Attributes;
  14. using ZhonTai.Admin.Core.Auth;
  15. namespace ZhonTai.Admin.Core.Db
  16. {
  17. public class DbHelper
  18. {
  19. /// <summary>
  20. /// 偏移时间
  21. /// </summary>
  22. public static TimeSpan TimeOffset;
  23. /// <summary>
  24. /// 创建数据库
  25. /// </summary>
  26. /// <param name="dbConfig"></param>
  27. /// <returns></returns>
  28. public async static Task CreateDatabaseAsync(DbConfig dbConfig)
  29. {
  30. if (!dbConfig.CreateDb || dbConfig.Type == DataType.Sqlite)
  31. {
  32. return;
  33. }
  34. var db = new FreeSqlBuilder()
  35. .UseConnectionString(dbConfig.Type, dbConfig.CreateDbConnectionString)
  36. .Build();
  37. try
  38. {
  39. Console.WriteLine("\r\n create database started");
  40. await db.Ado.ExecuteNonQueryAsync(dbConfig.CreateDbSql);
  41. Console.WriteLine(" create database succeed");
  42. }
  43. catch (Exception e)
  44. {
  45. Console.WriteLine($" create database failed.\n {e.Message}");
  46. }
  47. }
  48. /// <summary>
  49. /// 获得指定程序集表实体
  50. /// </summary>
  51. /// <param name="appConfig"></param>
  52. /// <returns></returns>
  53. public static Type[] GetEntityTypes(AppConfig appConfig)
  54. {
  55. Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries
  56. .Where(a => appConfig.AssemblyNames.Contains(a.Name) || a.Name == "ZhonTai.Admin")
  57. .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
  58. List<Type> entityTypes = new List<Type>();
  59. foreach (var assembly in assemblies)
  60. {
  61. foreach (Type type in assembly.GetExportedTypes())
  62. {
  63. foreach (Attribute attribute in type.GetCustomAttributes())
  64. {
  65. if (attribute is TableAttribute tableAttribute)
  66. {
  67. if (tableAttribute.DisableSyncStructure == false)
  68. {
  69. entityTypes.Add(type);
  70. }
  71. }
  72. }
  73. }
  74. }
  75. return entityTypes.ToArray();
  76. }
  77. /// <summary>
  78. /// 配置实体
  79. /// </summary>
  80. public static void ConfigEntity(IFreeSql db, AppConfig appConfig = null)
  81. {
  82. //租户生成和操作租户Id
  83. if (!appConfig.Tenant)
  84. {
  85. var iTenant = nameof(ITenant);
  86. var tenantId = nameof(ITenant.TenantId);
  87. //获得指定程序集表实体
  88. var entityTypes = GetEntityTypes(appConfig);
  89. foreach (var entityType in entityTypes)
  90. {
  91. if (entityType.GetInterfaces().Any(a => a.Name == iTenant))
  92. {
  93. db.CodeFirst.Entity(entityType, a =>
  94. {
  95. a.Ignore(tenantId);
  96. });
  97. }
  98. }
  99. }
  100. }
  101. /// <summary>
  102. /// 审计数据
  103. /// </summary>
  104. /// <param name="e"></param>
  105. /// <param name="timeOffset"></param>
  106. /// <param name="user"></param>
  107. public static void AuditValue(AuditValueEventArgs e, TimeSpan timeOffset, IUser user)
  108. {
  109. if (e.Property.GetCustomAttribute<ServerTimeAttribute>(false) != null
  110. && (e.Column.CsType == typeof(DateTime) || e.Column.CsType == typeof(DateTime?))
  111. && (e.Value == null || (DateTime)e.Value == default || (DateTime?)e.Value == default))
  112. {
  113. e.Value = DateTime.Now.Subtract(timeOffset);
  114. }
  115. if (e.Column.CsType == typeof(long)
  116. && e.Property.GetCustomAttribute<SnowflakeAttribute>(false) is SnowflakeAttribute snowflakeAttribute
  117. && snowflakeAttribute.Enable && (e.Value == null || (long)e.Value == default || (long?)e.Value == default))
  118. {
  119. e.Value = YitIdHelper.NextId();
  120. }
  121. if (user == null || user.Id <= 0)
  122. {
  123. return;
  124. }
  125. if (e.AuditValueType == AuditValueType.Insert)
  126. {
  127. switch (e.Property.Name)
  128. {
  129. case "CreatedUserId":
  130. if (e.Value == null || (long)e.Value == default || (long?)e.Value == default)
  131. {
  132. e.Value = user.Id;
  133. }
  134. break;
  135. case "CreatedUserName":
  136. if (e.Value == null || ((string)e.Value).IsNull())
  137. {
  138. e.Value = user.Name;
  139. }
  140. break;
  141. case "TenantId":
  142. if (e.Value == null || (long)e.Value == default || (long?)e.Value == default)
  143. {
  144. e.Value = user.TenantId;
  145. }
  146. break;
  147. }
  148. }
  149. else if (e.AuditValueType == AuditValueType.Update)
  150. {
  151. switch (e.Property.Name)
  152. {
  153. case "ModifiedUserId":
  154. e.Value = user.Id;
  155. break;
  156. case "ModifiedUserName":
  157. e.Value = user.Name;
  158. break;
  159. }
  160. }
  161. }
  162. /// <summary>
  163. /// 同步结构
  164. /// </summary>
  165. public static void SyncStructure(IFreeSql db, string msg = null, DbConfig dbConfig = null, AppConfig appConfig = null)
  166. {
  167. //打印结构比对脚本
  168. //var dDL = db.CodeFirst.GetComparisonDDLStatements<PermissionEntity>();
  169. //Console.WriteLine("\r\n " + dDL);
  170. //打印结构同步脚本
  171. //db.Aop.SyncStructureAfter += (s, e) =>
  172. //{
  173. // if (e.Sql.NotNull())
  174. // {
  175. // Console.WriteLine(" sync structure sql:\n" + e.Sql);
  176. // }
  177. //};
  178. // 同步结构
  179. var dbType = dbConfig.Type.ToString();
  180. Console.WriteLine($"\r\n {(msg.NotNull() ? msg : $"sync {dbType} structure")} started");
  181. if (dbConfig.Type == DataType.Oracle)
  182. {
  183. db.CodeFirst.IsSyncStructureToUpper = true;
  184. }
  185. //获得指定程序集表实体
  186. var entityTypes = GetEntityTypes(appConfig);
  187. db.CodeFirst.SyncStructure(entityTypes);
  188. Console.WriteLine($" {(msg.NotNull() ? msg : $"sync {dbType} structure")} succeed");
  189. }
  190. /// <summary>
  191. /// 同步数据审计方法
  192. /// </summary>
  193. /// <param name="s"></param>
  194. /// <param name="e"></param>
  195. private static void SyncDataAuditValue(object s, AuditValueEventArgs e)
  196. {
  197. var user = new { Id = 161223411986501, Name = "admin", TenantId = 161223412138053 };
  198. if (e.Property.GetCustomAttribute<ServerTimeAttribute>(false) != null
  199. && (e.Column.CsType == typeof(DateTime) || e.Column.CsType == typeof(DateTime?))
  200. && (e.Value == null || (DateTime)e.Value == default || (DateTime?)e.Value == default))
  201. {
  202. e.Value = DateTime.Now.Subtract(TimeOffset);
  203. }
  204. if (e.Column.CsType == typeof(long)
  205. && e.Property.GetCustomAttribute<SnowflakeAttribute>(false) != null
  206. && (e.Value == null || (long)e.Value == default || (long?)e.Value == default))
  207. {
  208. e.Value = YitIdHelper.NextId();
  209. }
  210. if (user == null || user.Id <= 0)
  211. {
  212. return;
  213. }
  214. if (e.AuditValueType == AuditValueType.Insert)
  215. {
  216. switch (e.Property.Name)
  217. {
  218. case "CreatedUserId":
  219. if (e.Value == null || (long)e.Value == default || (long?)e.Value == default)
  220. {
  221. e.Value = user.Id;
  222. }
  223. break;
  224. case "CreatedUserName":
  225. if (e.Value == null || ((string)e.Value).IsNull())
  226. {
  227. e.Value = user.Name;
  228. }
  229. break;
  230. case "TenantId":
  231. if (e.Value == null || (long)e.Value == default || (long?)e.Value == default)
  232. {
  233. e.Value = user.TenantId;
  234. }
  235. break;
  236. }
  237. }
  238. else if (e.AuditValueType == AuditValueType.Update)
  239. {
  240. switch (e.Property.Name)
  241. {
  242. case "ModifiedUserId":
  243. e.Value = user.Id;
  244. break;
  245. case "ModifiedUserName":
  246. e.Value = user.Name;
  247. break;
  248. }
  249. }
  250. }
  251. /// <summary>
  252. /// 同步数据
  253. /// </summary>
  254. /// <param name="db"></param>
  255. /// <param name="dbConfig"></param>
  256. /// <param name="appConfig"></param>
  257. /// <returns></returns>
  258. /// <exception cref="Exception"></exception>
  259. public static async Task SyncDataAsync(
  260. IFreeSql db,
  261. DbConfig dbConfig = null,
  262. AppConfig appConfig = null
  263. )
  264. {
  265. try
  266. {
  267. Console.WriteLine("\r\n sync data started");
  268. db.Aop.AuditValue += SyncDataAuditValue;
  269. Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries
  270. .Where(a => appConfig.AssemblyNames.Contains(a.Name) || a.Name == "ZhonTai.Admin")
  271. .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
  272. List<ISyncData> syncDatas = assemblies.Select(assembly => assembly.GetTypes()
  273. .Where(x => typeof(ISyncData).GetTypeInfo().IsAssignableFrom(x.GetTypeInfo()) && x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract))
  274. .SelectMany(registerTypes =>
  275. registerTypes.Select(registerType => (ISyncData)Activator.CreateInstance(registerType))).ToList();
  276. foreach (ISyncData syncData in syncDatas)
  277. {
  278. await syncData.SyncDataAsync(db, dbConfig, appConfig);
  279. }
  280. db.Aop.AuditValue -= SyncDataAuditValue;
  281. Console.WriteLine(" sync data succeed\r\n");
  282. }
  283. catch (Exception ex)
  284. {
  285. throw new Exception($" sync data failed.\n{ex.Message}");
  286. }
  287. }
  288. /// <summary>
  289. /// 生成数据
  290. /// </summary>
  291. /// <param name="db"></param>
  292. /// <param name="appConfig"></param>
  293. /// <returns></returns>
  294. /// <exception cref="Exception"></exception>
  295. public static async Task GenerateDataAsync(IFreeSql db, AppConfig appConfig = null)
  296. {
  297. try
  298. {
  299. Console.WriteLine("\r\n generate data started");
  300. Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries
  301. .Where(a => appConfig.AssemblyNames.Contains(a.Name) || a.Name == "ZhonTai.Admin")
  302. .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
  303. List<IGenerateData> generateDatas = assemblies.Select(assembly => assembly.GetTypes()
  304. .Where(x => typeof(IGenerateData).GetTypeInfo().IsAssignableFrom(x.GetTypeInfo()) && x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract))
  305. .SelectMany(registerTypes =>
  306. registerTypes.Select(registerType => (IGenerateData)Activator.CreateInstance(registerType))).ToList();
  307. foreach (IGenerateData generateData in generateDatas)
  308. {
  309. await generateData.GenerateDataAsync(db, appConfig);
  310. }
  311. Console.WriteLine(" generate data succeed\r\n");
  312. }
  313. catch (Exception ex)
  314. {
  315. throw new Exception($" generate data failed。\n{ex.Message}\r\n");
  316. }
  317. }
  318. }
  319. }