using Admin.Core.Common.Attributes; using Admin.Core.Common.Auth; using Admin.Core.Common.BaseModel; using Admin.Core.Common.Configs; using Admin.Core.Common.Extensions; using Admin.Core.Common.Helpers; using Admin.Core.Model.Admin; using Admin.Core.Model.Personnel; using Admin.Core.Repository.Admin.Output; using Admin.Core.Repository.Admin.Permission.Output; using Admin.Core.Repository.Admin.View.Output; using Admin.Core.Repository.Personnel.Output; using FreeSql; using FreeSql.Aop; using FreeSql.DataAnnotations; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Yitter.IdGenerator; namespace Admin.Core.Repository { 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("\r\n create database started"); 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() { List assemblyNames = new List() { "Admin.Core.Model" }; List entityTypes = new List(); foreach (var assemblyName in assemblyNames) { foreach (Type type in Assembly.Load(assemblyName).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) { //租户生成和操作租户Id if (!appConfig.Tenant) { var iTenant = nameof(ITenant); var tenantId = nameof(ITenant.TenantId); //获得指定程序集表实体 var entityTypes = GetEntityTypes(); 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 "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 void SyncStructure(IFreeSql db, string msg = null, DbConfig dbConfig = null, AppConfig appConfig = null) { //打印结构比对脚本 //var dDL = db.CodeFirst.GetComparisonDDLStatements(); //Console.WriteLine("\r\n " + 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($"\r\n {(msg.NotNull() ? msg : $"sync {dbType} structure")} started"); if (dbConfig.Type == DataType.Oracle) { db.CodeFirst.IsSyncStructureToUpper = true; } //获得指定程序集表实体 var entityTypes = GetEntityTypes(); db.CodeFirst.SyncStructure(entityTypes); Console.WriteLine($" {(msg.NotNull() ? msg : $"sync {dbType} structure")} succeed"); } /// /// 检查实体属性是否为自增长 /// /// /// private static bool CheckIdentity() where T : class { var isIdentity = false; var properties = typeof(T).GetProperties(); foreach (var property in properties) { if (property.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault() is ColumnAttribute columnAttribute && columnAttribute.IsIdentity) { isIdentity = true; break; } } return isIdentity; } /// /// 初始化数据表数据 /// /// /// /// /// /// /// /// private static async Task InitDtDataAsync( IFreeSql db, IUnitOfWork unitOfWork, System.Data.Common.DbTransaction tran, T[] data, DbConfig dbConfig = null ) where T : class, new() { var table = typeof(T).GetCustomAttributes(typeof(TableAttribute), false).FirstOrDefault() as TableAttribute; var tableName = table.Name; try { if (await db.Queryable().AnyAsync()) { Console.WriteLine($" table: {tableName} record already exists"); return; } if (!(data?.Length > 0)) { Console.WriteLine($" table: {tableName} import data []"); return; } var repo = db.GetRepositoryBase(); var insert = db.Insert(); if (unitOfWork != null) { repo.UnitOfWork = unitOfWork; insert = insert.WithTransaction(tran); } var isIdentity = CheckIdentity(); if (isIdentity) { if (dbConfig.Type == DataType.SqlServer) { var insrtSql = insert.AppendData(data).InsertIdentity().ToSql(); await repo.Orm.Ado.ExecuteNonQueryAsync($"SET IDENTITY_INSERT {tableName} ON\n {insrtSql} \nSET IDENTITY_INSERT {tableName} OFF"); } else { await insert.AppendData(data).InsertIdentity().ExecuteAffrowsAsync(); } } else { repo.DbContextOptions.EnableAddOrUpdateNavigateList = true; await repo.InsertAsync(data); } Console.WriteLine($" table: {tableName} sync data succeed"); } catch (Exception ex) { Console.WriteLine($" table: {tableName} sync data failed.\n{ex.Message}"); } } /// /// 同步数据审计方法 /// /// /// 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 { //db.Aop.CurdBefore += (s, e) => //{ // Console.WriteLine($"{e.Sql}\r\n"); //}; Console.WriteLine("\r\n sync data started"); db.Aop.AuditValue += SyncDataAuditValue; var fileName = appConfig.Tenant ? "data-share.json" : "data.json"; var filePath = Path.Combine(AppContext.BaseDirectory, $"Db/Data/{fileName}").ToPath(); var jsonData = FileHelper.ReadFile(filePath); var data = JsonConvert.DeserializeObject(jsonData); using (var uow = db.CreateUnitOfWork()) using (var tran = uow.GetOrBeginTransaction()) { var dualRepo = db.GetRepositoryBase(); dualRepo.UnitOfWork = uow; if (!await dualRepo.Select.AnyAsync()) { await dualRepo.InsertAsync(new DualEntity { }); } //admin await InitDtDataAsync(db, uow, tran, data.DictionaryTypes, dbConfig); await InitDtDataAsync(db, uow, tran, data.Dictionaries, dbConfig); await InitDtDataAsync(db, uow, tran, data.ApiTree, dbConfig); await InitDtDataAsync(db, uow, tran, data.ViewTree, dbConfig); await InitDtDataAsync(db, uow, tran, data.PermissionTree, dbConfig); await InitDtDataAsync(db, uow, tran, data.Users, dbConfig); await InitDtDataAsync(db, uow, tran, data.Roles, dbConfig); await InitDtDataAsync(db, uow, tran, data.UserRoles, dbConfig); await InitDtDataAsync(db, uow, tran, data.RolePermissions, dbConfig); await InitDtDataAsync(db, uow, tran, data.Tenants, dbConfig); await InitDtDataAsync(db, uow, tran, data.TenantPermissions, dbConfig); await InitDtDataAsync(db, uow, tran, data.PermissionApis, dbConfig); //人事 await InitDtDataAsync(db, uow, tran, data.Positions, dbConfig); await InitDtDataAsync(db, uow, tran, data.OrganizationTree, dbConfig); await InitDtDataAsync(db, uow, tran, data.Employees, dbConfig); uow.Commit(); } db.Aop.AuditValue -= SyncDataAuditValue; Console.WriteLine(" sync data succeed\r\n"); } catch (Exception ex) { throw new Exception($" sync data failed.\n{ex.Message}"); } } /// /// 生成极简数据 /// /// /// /// public static async Task GenerateSimpleJsonDataAsync(IFreeSql db, AppConfig appConfig = null) { try { Console.WriteLine("\r\n generate data started"); #region 数据表 //admin #region 数据字典 var dictionaryTypes = await db.Queryable().ToListAsync(); var dictionaries = await db.Queryable().ToListAsync(); #endregion #region 接口 var apis = await db.Queryable().ToListAsync(); var apiTree = apis.ToTree((r, c) => { return c.ParentId == 0; }, (r, c) => { return r.Id == c.ParentId; }, (r, datalist) => { r.Childs ??= new List(); r.Childs.AddRange(datalist); }); #endregion #region 视图 var views = await db.Queryable().ToListAsync(); var viewTree = views.ToTree((r, c) => { return c.ParentId == 0; }, (r, c) => { return r.Id == c.ParentId; }, (r, datalist) => { r.Childs ??= new List(); r.Childs.AddRange(datalist); }); #endregion #region 权限 var permissions = await db.Queryable().ToListAsync(); var permissionTree = permissions.ToTree((r, c) => { return c.ParentId == 0; }, (r, c) => { return r.Id == c.ParentId; }, (r, datalist) => { r.Childs ??= new List(); r.Childs.AddRange(datalist); }); #endregion #region 用户 var users = await db.Queryable().ToListAsync(); #endregion #region 角色 var roles = await db.Queryable().ToListAsync(); #endregion #region 用户角色 var userRoles = await db.Queryable().ToListAsync(a => new { a.Id, a.UserId, a.RoleId }); #endregion #region 角色权限 var rolePermissions = await db.Queryable().ToListAsync(a => new { a.Id, a.RoleId, a.PermissionId }); #endregion #region 租户 var tenants = await db.Queryable().ToListAsync(a => new { a.Id, a.UserId, a.RoleId, a.Name, a.Code, a.RealName, a.Phone, a.Email, a.TenantType, a.DataIsolationType, a.DbType, a.ConnectionString, a.IdleTime, a.Description }); #endregion #region 租户权限 var tenantPermissions = await db.Queryable().ToListAsync(a => new { a.Id, a.TenantId, a.PermissionId }); #endregion #region 权限接口 var permissionApis = await db.Queryable().ToListAsync(a => new { a.Id, a.PermissionId, a.ApiId }); #endregion //人事 #region 部门 var organizations = await db.Queryable().ToListAsync(); var organizationTree = organizations.ToTree((r, c) => { return c.ParentId == 0; }, (r, c) => { return r.Id == c.ParentId; }, (r, datalist) => { r.Childs ??= new List(); r.Childs.AddRange(datalist); }); #endregion #region 岗位 var positions = await db.Queryable().ToListAsync(); #endregion #region 员工 var employees = await db.Queryable().ToListAsync(); #endregion #endregion if (!(users?.Count > 0)) { return; } #region 生成数据 var settings = new JsonSerializerSettings(); settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); settings.NullValueHandling = NullValueHandling.Ignore; settings.DefaultValueHandling = DefaultValueHandling.Ignore; var jsonData = JsonConvert.SerializeObject(new { dictionaries, dictionaryTypes, apis, apiTree, viewTree, permissionTree, users, roles, userRoles, rolePermissions, tenants, tenantPermissions, permissionApis, organizationTree, positions, employees }, //Formatting.Indented, settings ); var isTenant = appConfig.Tenant; var fileName = isTenant ? "data-share.json" : "data.json"; var filePath = Path.Combine(Directory.GetCurrentDirectory(), $"Db/Data/{fileName}").ToPath(); FileHelper.WriteFile(filePath, jsonData); if (isTenant) { var tenantId = tenants.Where(a => a.Code.ToLower() == "zhontai").FirstOrDefault().Id; organizationTree = organizations.Where(a => a.TenantId == tenantId).ToList().ToTree((r, c) => { return c.ParentId == 0; }, (r, c) => { return r.Id == c.ParentId; }, (r, datalist) => { r.Childs ??= new List(); r.Childs.AddRange(datalist); }); jsonData = JsonConvert.SerializeObject(new { dictionaries = dictionaries.Where(a=>a.TenantId == tenantId), dictionaryTypes = dictionaryTypes.Where(a => a.TenantId == tenantId), apis, apiTree, viewTree, permissionTree, users = users.Where(a => a.TenantId == tenantId), roles = roles.Where(a => a.TenantId == tenantId), userRoles, rolePermissions, tenants, tenantPermissions, permissionApis, organizationTree }, settings ); filePath = Path.Combine(Directory.GetCurrentDirectory(), "Db/Data/data.json").ToPath(); FileHelper.WriteFile(filePath, jsonData); } #endregion Console.WriteLine(" generate data succeed\r\n"); } catch (Exception ex) { throw new Exception($" generate data failed。\n{ex.Message}\r\n"); } } } }