abp
/Data
/
MyProjectNameDbMigrationService.cs
203 строки · 6.2 Кб
1using System.Diagnostics;
2using System.Runtime.InteropServices;
3using Microsoft.Extensions.Logging.Abstractions;
4using Volo.Abp.Data;
5using Volo.Abp.DependencyInjection;
6using Volo.Abp.Identity;
7using Volo.Abp.MultiTenancy;
8using Volo.Abp.TenantManagement;
9
10namespace MyCompanyName.MyProjectName.Data;
11
12public class MyProjectNameDbMigrationService : ITransientDependency
13{
14public ILogger<MyProjectNameDbMigrationService> Logger { get; set; }
15
16private readonly IDataSeeder _dataSeeder;
17private readonly MyProjectNameEFCoreDbSchemaMigrator _dbSchemaMigrator;
18private readonly ITenantRepository _tenantRepository;
19private readonly ICurrentTenant _currentTenant;
20
21public MyProjectNameDbMigrationService(
22IDataSeeder dataSeeder,
23MyProjectNameEFCoreDbSchemaMigrator dbSchemaMigrator,
24ITenantRepository tenantRepository,
25ICurrentTenant currentTenant)
26{
27_dataSeeder = dataSeeder;
28_dbSchemaMigrator = dbSchemaMigrator;
29_tenantRepository = tenantRepository;
30_currentTenant = currentTenant;
31
32Logger = NullLogger<MyProjectNameDbMigrationService>.Instance;
33}
34
35public async Task MigrateAsync()
36{
37var initialMigrationAdded = AddInitialMigrationIfNotExist();
38
39if (initialMigrationAdded)
40{
41return;
42}
43
44Logger.LogInformation("Started database migrations...");
45
46await MigrateDatabaseSchemaAsync();
47await SeedDataAsync();
48
49Logger.LogInformation($"Successfully completed host database migrations.");
50
51var tenants = await _tenantRepository.GetListAsync(includeDetails: true);
52
53var migratedDatabaseSchemas = new HashSet<string>();
54foreach (var tenant in tenants)
55{
56using (_currentTenant.Change(tenant.Id))
57{
58if (tenant.ConnectionStrings.Any())
59{
60var tenantConnectionStrings = tenant.ConnectionStrings
61.Select(x => x.Value)
62.ToList();
63
64if (!migratedDatabaseSchemas.IsSupersetOf(tenantConnectionStrings))
65{
66await MigrateDatabaseSchemaAsync(tenant);
67
68migratedDatabaseSchemas.AddIfNotContains(tenantConnectionStrings);
69}
70}
71
72await SeedDataAsync(tenant);
73}
74
75Logger.LogInformation($"Successfully completed {tenant.Name} tenant database migrations.");
76}
77
78Logger.LogInformation("Successfully completed all database migrations.");
79Logger.LogInformation("You can safely end this process...");
80}
81
82private async Task MigrateDatabaseSchemaAsync(Tenant? tenant = null)
83{
84Logger.LogInformation($"Migrating schema for {(tenant == null ? "host" : tenant.Name + " tenant")} database...");
85await _dbSchemaMigrator.MigrateAsync();
86}
87
88private async Task SeedDataAsync(Tenant? tenant = null)
89{
90Logger.LogInformation($"Executing {(tenant == null ? "host" : tenant.Name + " tenant")} database seed...");
91
92await _dataSeeder.SeedAsync(new DataSeedContext(tenant?.Id)
93.WithProperty(IdentityDataSeedContributor.AdminEmailPropertyName, IdentityDataSeedContributor.AdminEmailDefaultValue)
94.WithProperty(IdentityDataSeedContributor.AdminPasswordPropertyName, IdentityDataSeedContributor.AdminPasswordDefaultValue)
95);
96}
97
98private bool AddInitialMigrationIfNotExist()
99{
100try
101{
102if (!DbMigrationsProjectExists())
103{
104return false;
105}
106}
107catch (Exception)
108{
109return false;
110}
111
112try
113{
114if (!MigrationsFolderExists())
115{
116AddInitialMigration();
117return true;
118}
119else
120{
121return false;
122}
123}
124catch (Exception e)
125{
126Logger.LogWarning("Couldn't determinate if any migrations exist : " + e.Message);
127return false;
128}
129}
130
131private bool DbMigrationsProjectExists()
132{
133return Directory.Exists(GetEntityFrameworkCoreProjectFolderPath());
134}
135
136private bool MigrationsFolderExists()
137{
138var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath();
139
140return Directory.Exists(Path.Combine(dbMigrationsProjectFolder, "Migrations"));
141}
142
143private void AddInitialMigration()
144{
145Logger.LogInformation("Creating initial migration...");
146
147string argumentPrefix;
148string fileName;
149
150if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
151{
152argumentPrefix = "-c";
153fileName = "/bin/bash";
154}
155else
156{
157argumentPrefix = "/C";
158fileName = "cmd.exe";
159}
160
161var procStartInfo = new ProcessStartInfo(fileName,
162$"{argumentPrefix} \"abp create-migration-and-run-migrator \"{GetEntityFrameworkCoreProjectFolderPath()}\" --nolayers\""
163);
164
165try
166{
167Process.Start(procStartInfo);
168}
169catch (Exception)
170{
171throw new Exception("Couldn't run ABP CLI...");
172}
173}
174
175private string GetEntityFrameworkCoreProjectFolderPath()
176{
177var slnDirectoryPath = GetSolutionDirectoryPath();
178
179if (slnDirectoryPath == null)
180{
181throw new Exception("Solution folder not found!");
182}
183
184return Path.Combine(slnDirectoryPath, "MyCompanyName.MyProjectName.Host");
185}
186
187private string? GetSolutionDirectoryPath()
188{
189var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
190
191while (currentDirectory != null && Directory.GetParent(currentDirectory.FullName) != null)
192{
193currentDirectory = Directory.GetParent(currentDirectory.FullName);
194
195if (currentDirectory != null && Directory.GetFiles(currentDirectory.FullName).FirstOrDefault(f => f.EndsWith(".sln")) != null)
196{
197return currentDirectory.FullName;
198}
199}
200
201return null;
202}
203}
204