MultiTenantMigrateExecuter.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. using Abp.Dependency;
  2. using Abp.Domain.Repositories;
  3. using Abp.Domain.Uow;
  4. using Abp.Extensions;
  5. using Abp.Runtime.Security;
  6. using System.Data.Common;
  7. using VberAdmin.EntityFrameworkCore;
  8. using VberAdmin.Seed;
  9. using VberZero.BaseSystem.MultiTenancy;
  10. using VberZero.Data;
  11. using VberZero.MultiTenancy;
  12. namespace VberAdmin.Migrator;
  13. public class MultiTenantMigrateExecuter : ITransientDependency
  14. {
  15. private readonly Log _log;
  16. private readonly VberAdminDbMigrator _migrator;
  17. private readonly IRepository<Tenant> _tenantRepository;
  18. private readonly IDbPerTenantConnectionStringResolver _connectionStringResolver;
  19. public MultiTenantMigrateExecuter(
  20. VberAdminDbMigrator migrator,
  21. IRepository<Tenant> tenantRepository,
  22. Log log,
  23. IDbPerTenantConnectionStringResolver connectionStringResolver)
  24. {
  25. _log = log;
  26. _migrator = migrator;
  27. _tenantRepository = tenantRepository;
  28. _connectionStringResolver = connectionStringResolver;
  29. }
  30. public bool Run(bool skipConnVerification)
  31. {
  32. var hostConnStr = CensorConnectionString(_connectionStringResolver.GetNameOrConnectionString(new ConnectionStringResolveArgs(Abp.MultiTenancy.MultiTenancySides.Host)));
  33. if (hostConnStr.IsNullOrWhiteSpace())
  34. {
  35. _log.Write("配置文件应包含名为 “Default” 的连接字符串");
  36. return false;
  37. }
  38. _log.Write("主机数据库: " + ConnectionStringHelper.GetConnectionString(hostConnStr));
  39. if (!skipConnVerification)
  40. {
  41. _log.Write("继续迁移此主机数据库和所有租户..? (Y/N)");
  42. _log.Write("5秒后自动开始");
  43. var result = false;
  44. Task.Factory.StartNew(() =>
  45. {
  46. var command = Console.ReadLine();
  47. if (!command.IsIn("Y", "y"))
  48. {
  49. result = true;
  50. }
  51. }).Wait(5 * 1000);
  52. if (result)
  53. {
  54. _log.Write("迁移取消。");
  55. return false;
  56. }
  57. }
  58. _log.Write("HOST 数据库迁移开始...");
  59. try
  60. {
  61. _migrator.CreateOrMigrateForHost(SeedHelper.SeedHostDb);
  62. }
  63. catch (Exception ex)
  64. {
  65. _log.Write("迁移主机数据库时发生错误:");
  66. _log.Write(ex.ToString());
  67. _log.Write("取消的迁移。");
  68. return false;
  69. }
  70. _log.Write("HOST 数据库迁移完成。");
  71. _log.Write("--------------------------------------------------------");
  72. var migratedDatabases = new HashSet<string>();
  73. var tenants = _tenantRepository.GetAllList(t => t.ConnectionString != null && t.ConnectionString != "");
  74. for (var i = 0; i < tenants.Count; i++)
  75. {
  76. var tenant = tenants[i];
  77. _log.Write($"租户数据库迁移开始... ({(i + 1)} / {tenants.Count})");
  78. _log.Write("Name : " + tenant.Name);
  79. _log.Write("TenancyName : " + tenant.TenancyName);
  80. _log.Write("Tenant Id : " + tenant.Id);
  81. _log.Write("Connection string : " + SimpleStringCipher.Instance.Decrypt(tenant.ConnectionString));
  82. if (!migratedDatabases.Contains(tenant.ConnectionString))
  83. {
  84. try
  85. {
  86. _migrator.CreateOrMigrateForTenant(tenant);
  87. }
  88. catch (Exception ex)
  89. {
  90. _log.Write("租户数据库迁移过程中出现错误:");
  91. _log.Write(ex.ToString());
  92. _log.Write("跳过这个租户并将继续为其他租户...");
  93. }
  94. migratedDatabases.Add(tenant.ConnectionString);
  95. }
  96. else
  97. {
  98. _log.Write("此数据库之前已经迁移过(同一数据库中有多个租户)。 跳过它....");
  99. }
  100. _log.Write($"租户数据库迁移已完成。 ({(i + 1)} / {tenants.Count})");
  101. _log.Write("--------------------------------------------------------");
  102. }
  103. _log.Write("所有数据库都已迁移。");
  104. return true;
  105. }
  106. private static string CensorConnectionString(string connectionString)
  107. {
  108. var builder = new DbConnectionStringBuilder { ConnectionString = connectionString };
  109. var keysToMask = new[] { "password", "pwd", "user id", "uid" };
  110. foreach (var key in keysToMask)
  111. {
  112. if (builder.ContainsKey(key))
  113. {
  114. builder[key] = "*****";
  115. }
  116. }
  117. return builder.ToString();
  118. }
  119. }