using Abp.Dependency; using Abp.Domain.Repositories; using Abp.Domain.Uow; using Abp.Extensions; using Abp.Runtime.Security; using System.Data.Common; using VberAdmin.EntityFrameworkCore; using VberAdmin.Seed; using VberZero.BaseSystem.MultiTenancy; using VberZero.Data; using VberZero.MultiTenancy; namespace VberAdmin.Migrator; public class MultiTenantMigrateExecuter : ITransientDependency { private readonly Log _log; private readonly VberAdminDbMigrator _migrator; private readonly IRepository _tenantRepository; private readonly IDbPerTenantConnectionStringResolver _connectionStringResolver; public MultiTenantMigrateExecuter( VberAdminDbMigrator migrator, IRepository tenantRepository, Log log, IDbPerTenantConnectionStringResolver connectionStringResolver) { _log = log; _migrator = migrator; _tenantRepository = tenantRepository; _connectionStringResolver = connectionStringResolver; } public bool Run(bool skipConnVerification) { var hostConnStr = CensorConnectionString(_connectionStringResolver.GetNameOrConnectionString(new ConnectionStringResolveArgs(Abp.MultiTenancy.MultiTenancySides.Host))); if (hostConnStr.IsNullOrWhiteSpace()) { _log.Write("配置文件应包含名为 “Default” 的连接字符串"); return false; } _log.Write("主机数据库: " + ConnectionStringHelper.GetConnectionString(hostConnStr)); if (!skipConnVerification) { _log.Write("继续迁移此主机数据库和所有租户..? (Y/N)"); _log.Write("5秒后自动开始"); var result = false; Task.Factory.StartNew(() => { var command = Console.ReadLine(); if (!command.IsIn("Y", "y")) { result = true; } }).Wait(5 * 1000); if (result) { _log.Write("迁移取消。"); return false; } } _log.Write("HOST 数据库迁移开始..."); try { _migrator.CreateOrMigrateForHost(SeedHelper.SeedHostDb); } catch (Exception ex) { _log.Write("迁移主机数据库时发生错误:"); _log.Write(ex.ToString()); _log.Write("取消的迁移。"); return false; } _log.Write("HOST 数据库迁移完成。"); _log.Write("--------------------------------------------------------"); var migratedDatabases = new HashSet(); var tenants = _tenantRepository.GetAllList(t => t.ConnectionString != null && t.ConnectionString != ""); for (var i = 0; i < tenants.Count; i++) { var tenant = tenants[i]; _log.Write($"租户数据库迁移开始... ({(i + 1)} / {tenants.Count})"); _log.Write("Name : " + tenant.Name); _log.Write("TenancyName : " + tenant.TenancyName); _log.Write("Tenant Id : " + tenant.Id); _log.Write("Connection string : " + SimpleStringCipher.Instance.Decrypt(tenant.ConnectionString)); if (!migratedDatabases.Contains(tenant.ConnectionString)) { try { _migrator.CreateOrMigrateForTenant(tenant); } catch (Exception ex) { _log.Write("租户数据库迁移过程中出现错误:"); _log.Write(ex.ToString()); _log.Write("跳过这个租户并将继续为其他租户..."); } migratedDatabases.Add(tenant.ConnectionString); } else { _log.Write("此数据库之前已经迁移过(同一数据库中有多个租户)。 跳过它...."); } _log.Write($"租户数据库迁移已完成。 ({(i + 1)} / {tenants.Count})"); _log.Write("--------------------------------------------------------"); } _log.Write("所有数据库都已迁移。"); return true; } private static string CensorConnectionString(string connectionString) { var builder = new DbConnectionStringBuilder { ConnectionString = connectionString }; var keysToMask = new[] { "password", "pwd", "user id", "uid" }; foreach (var key in keysToMask) { if (builder.ContainsKey(key)) { builder[key] = "*****"; } } return builder.ToString(); } }