using Microsoft.Extensions.DependencyModel; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using FreeSql; using FreeSql.Aop; using FreeSql.DataAnnotations; using Yitter.IdGenerator; using ZhonTai.Admin.Core.Configs; using ZhonTai.Admin.Core.Entities; using ZhonTai.Admin.Core.Attributes; using ZhonTai.Admin.Core.Auth; using System.IO; using ZhonTai.Common.Helpers; using ZhonTai.Admin.Core.Db.Data; namespace ZhonTai.Admin.Core.Db; public class DbHelper { /// /// 偏移时间 /// public static TimeSpan TimeOffset; /// /// 创建数据库 /// /// /// public async static Task CreateDatabaseAsync(DbConfig dbConfig) { if (!dbConfig.CreateDb || dbConfig.Type == DataType.Sqlite) { return; } var db = new FreeSqlBuilder() .UseConnectionString(dbConfig.Type, dbConfig.CreateDbConnectionString) .Build(); try { Console.WriteLine($"{Environment.NewLine} create database started"); var filePath = Path.Combine(AppContext.BaseDirectory, "Configs/createdbsql.txt").ToPath(); if (File.Exists(filePath)) { var createDbSql = FileHelper.ReadFile(filePath); if (createDbSql.NotNull()) { dbConfig.CreateDbSql = createDbSql; } } await db.Ado.ExecuteNonQueryAsync(dbConfig.CreateDbSql); Console.WriteLine(" create database succeed"); } catch (Exception e) { Console.WriteLine($" create database failed.\n {e.Message}"); } } /// /// 获得指定程序集表实体 /// /// /// public static Type[] GetEntityTypes(string[] assemblyNames) { if(!(assemblyNames?.Length > 0)) { return null; } Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries .Where(a => assemblyNames.Contains(a.Name)) .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray(); var entityTypes = new List(); foreach (var assembly in assemblies) { foreach (Type type in assembly.GetExportedTypes()) { foreach (Attribute attribute in type.GetCustomAttributes()) { if (attribute is TableAttribute tableAttribute) { if (tableAttribute.DisableSyncStructure == false) { entityTypes.Add(type); } } } } } return entityTypes.ToArray(); } /// /// 配置实体 /// /// /// /// public static void ConfigEntity(IFreeSql db, AppConfig appConfig = null, DbConfig dbConfig = null) { //租户生成和操作租户Id if (!appConfig.Tenant) { var iTenant = nameof(ITenant); var tenantId = nameof(ITenant.TenantId); //获得指定程序集表实体 var entityTypes = GetEntityTypes(dbConfig.AssemblyNames); foreach (var entityType in entityTypes) { if (entityType.GetInterfaces().Any(a => a.Name == iTenant)) { db.CodeFirst.Entity(entityType, a => { a.Ignore(tenantId); }); } } } } /// /// 审计数据 /// /// /// /// public static void AuditValue(AuditValueEventArgs e, TimeSpan timeOffset, IUser user) { if (e.Property.GetCustomAttribute(false) != null && (e.Column.CsType == typeof(DateTime) || e.Column.CsType == typeof(DateTime?)) && (e.Value == null || (DateTime)e.Value == default || (DateTime?)e.Value == default)) { e.Value = DateTime.Now.Subtract(timeOffset); } if (e.Column.CsType == typeof(long) && e.Property.GetCustomAttribute(false) is SnowflakeAttribute snowflakeAttribute && snowflakeAttribute.Enable && (e.Value == null || (long)e.Value == default || (long?)e.Value == default)) { e.Value = YitIdHelper.NextId(); } if (user == null || user.Id <= 0) { return; } if (e.AuditValueType == AuditValueType.Insert) { switch (e.Property.Name) { case "OwnerId": case "CreatedUserId": if (e.Value == null || (long)e.Value == default || (long?)e.Value == default) { e.Value = user.Id; } break; case "CreatedUserName": if (e.Value == null || ((string)e.Value).IsNull()) { e.Value = user.UserName; } break; case "OwnerOrgId": if (e.Value == null || (long)e.Value == default || (long?)e.Value == default) { e.Value = user.DataPermission?.OrgId; } break; case "TenantId": if (e.Value == null || (long)e.Value == default || (long?)e.Value == default) { e.Value = user.TenantId; } break; } } else if (e.AuditValueType == AuditValueType.Update) { switch (e.Property.Name) { case "ModifiedUserId": e.Value = user.Id; break; case "ModifiedUserName": e.Value = user.UserName; break; } } } /// /// 同步结构 /// public static void SyncStructure(IFreeSql db, string msg = null, DbConfig dbConfig = null, AppConfig appConfig = null) { //打印结构比对脚本 //var dDL = db.CodeFirst.GetComparisonDDLStatements(); //Console.WriteLine($"{Environment.NewLine} " + dDL); //打印结构同步脚本 //db.Aop.SyncStructureAfter += (s, e) => //{ // if (e.Sql.NotNull()) // { // Console.WriteLine(" sync structure sql:\n" + e.Sql); // } //}; // 同步结构 var dbType = dbConfig.Type.ToString(); Console.WriteLine($"{Environment.NewLine} {(msg.NotNull() ? msg : $"sync {dbType} structure")} started"); if (dbConfig.Type == DataType.Oracle) { db.CodeFirst.IsSyncStructureToUpper = true; } //获得指定程序集表实体 var entityTypes = GetEntityTypes(dbConfig.AssemblyNames); db.CodeFirst.SyncStructure(entityTypes); Console.WriteLine($" {(msg.NotNull() ? msg : $"sync {dbType} structure")} succeed"); } /// /// 同步数据审计方法 /// /// /// private static void SyncDataAuditValue(object s, AuditValueEventArgs e) { var user = new { Id = 161223411986501, Name = "admin", TenantId = 161223412138053 }; if (e.Property.GetCustomAttribute(false) != null && (e.Column.CsType == typeof(DateTime) || e.Column.CsType == typeof(DateTime?)) && (e.Value == null || (DateTime)e.Value == default || (DateTime?)e.Value == default)) { e.Value = DateTime.Now.Subtract(TimeOffset); } if (e.Column.CsType == typeof(long) && e.Property.GetCustomAttribute(false) != null && (e.Value == null || (long)e.Value == default || (long?)e.Value == default)) { e.Value = YitIdHelper.NextId(); } if (user == null || user.Id <= 0) { return; } if (e.AuditValueType == AuditValueType.Insert) { switch (e.Property.Name) { case "CreatedUserId": if (e.Value == null || (long)e.Value == default || (long?)e.Value == default) { e.Value = user.Id; } break; case "CreatedUserName": if (e.Value == null || ((string)e.Value).IsNull()) { e.Value = user.Name; } break; case "TenantId": if (e.Value == null || (long)e.Value == default || (long?)e.Value == default) { e.Value = user.TenantId; } break; } } else if (e.AuditValueType == AuditValueType.Update) { switch (e.Property.Name) { case "ModifiedUserId": e.Value = user.Id; break; case "ModifiedUserName": e.Value = user.Name; break; } } } /// /// 同步数据 /// /// /// /// /// /// public static async Task SyncDataAsync( IFreeSql db, DbConfig dbConfig = null, AppConfig appConfig = null ) { try { Console.WriteLine($"{Environment.NewLine} sync data started"); if (dbConfig.AssemblyNames?.Length > 0) { db.Aop.AuditValue += SyncDataAuditValue; Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries .Where(a => dbConfig.AssemblyNames.Contains(a.Name)) .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray(); List syncDatas = assemblies.Select(assembly => assembly.GetTypes() .Where(x => typeof(ISyncData).GetTypeInfo().IsAssignableFrom(x.GetTypeInfo()) && x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract)) .SelectMany(registerTypes => registerTypes.Select(registerType => (ISyncData)Activator.CreateInstance(registerType))).ToList(); foreach (ISyncData syncData in syncDatas) { await syncData.SyncDataAsync(db, dbConfig, appConfig); } db.Aop.AuditValue -= SyncDataAuditValue; } Console.WriteLine($" sync data succeed{Environment.NewLine}"); } catch (Exception ex) { throw new Exception($" sync data failed.\n{ex.Message}"); } } /// /// 生成数据 /// /// /// /// /// /// public static async Task GenerateDataAsync(IFreeSql db, AppConfig appConfig = null, DbConfig dbConfig = null) { try { Console.WriteLine($"{Environment.NewLine} generate data started"); if (dbConfig.AssemblyNames?.Length > 0) { Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries .Where(a => dbConfig.AssemblyNames.Contains(a.Name)) .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray(); List generateDatas = assemblies.Select(assembly => assembly.GetTypes() .Where(x => typeof(IGenerateData).GetTypeInfo().IsAssignableFrom(x.GetTypeInfo()) && x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract)) .SelectMany(registerTypes => registerTypes.Select(registerType => (IGenerateData)Activator.CreateInstance(registerType))).ToList(); foreach (IGenerateData generateData in generateDatas) { await generateData.GenerateDataAsync(db, appConfig); } } Console.WriteLine($" generate data succeed{Environment.NewLine}"); } catch (Exception ex) { throw new Exception($" generate data failed。\n{ex.Message}{Environment.NewLine}"); } } }