schangxiang@126.com
2025-05-19 ed231e8624dd3b5ad021ea02cb0818d9fdfc4eb1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
 
namespace CMS.Plugin.PipeLineLems.Domain.Data;
 
/// <summary>
/// 数据库迁移服务
/// </summary>
public class CMSPluginDbMigrationService : ITransientDependency
{
    private readonly IDataSeeder _dataSeeder;
    private readonly IEnumerable<ICMSPluginDbSchemaMigrator> _dbSchemaMigrators;
    private readonly ILogger<CMSPluginDbMigrationService> _logger;
 
    /// <summary>
    /// Initializes a new instance of the <see cref="CMSPluginDbMigrationService"/> class.
    /// </summary>
    /// <param name="dataSeeder">The data seeder.</param>
    /// <param name="dbSchemaMigrators">The database schema migrators.</param>
    /// <param name="logger">The logger.</param>
    public CMSPluginDbMigrationService(IDataSeeder dataSeeder,
        IEnumerable<ICMSPluginDbSchemaMigrator> dbSchemaMigrators, ILogger<CMSPluginDbMigrationService> logger)
    {
        _dataSeeder = dataSeeder;
        _dbSchemaMigrators = dbSchemaMigrators;
        _logger = logger;
    }
 
    /// <summary>
    /// Migrates the asynchronous.
    /// </summary>
    public async Task MigrateAsync()
    {
        var initialMigrationAdded = AddInitialMigrationIfNotExist();
 
        if (initialMigrationAdded)
        {
            return;
        }
 
        _logger.LogDebug("Started database migrations...");
 
        await MigrateDatabaseSchemaAsync();
        await SeedDataAsync();
 
        _logger.LogDebug($"Successfully completed host database migrations.");
        _logger.LogDebug("You can safely end this process...");
    }
 
    /// <summary>
    /// Migrates the database schema asynchronous.
    /// </summary>
    private async Task MigrateDatabaseSchemaAsync()
    {
        _logger.LogDebug($"Migrating schema for database...");
 
        foreach (var migrator in _dbSchemaMigrators)
        {
            await migrator.MigrateAsync();
        }
    }
 
    /// <summary>
    /// Seeds the data asynchronous.
    /// </summary>
    private async Task SeedDataAsync()
    {
        _logger.LogDebug($"Executing database seed...");
 
        await _dataSeeder.SeedAsync(new DataSeedContext().WithProperty(CMSPluginDbProperties.ConnectionStringName, CMSPluginDbProperties.ConnectionStringName));
    }
 
    /// <summary>
    /// Adds the initial migration if not exist.
    /// </summary>
    /// <returns></returns>
    private bool AddInitialMigrationIfNotExist()
    {
        try
        {
            if (!DbMigrationsProjectExists())
            {
                return false;
            }
        }
        catch (Exception)
        {
            return false;
        }
 
        try
        {
            if (!MigrationsFolderExists())
            {
                AddInitialMigration();
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (Exception e)
        {
            _logger.LogWarning("Couldn't determinate if any migrations exist : " + e.Message);
            return false;
        }
    }
 
    /// <summary>
    /// Databases the migrations project exists.
    /// </summary>
    /// <returns></returns>
    private bool DbMigrationsProjectExists()
    {
        var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath();
 
        return dbMigrationsProjectFolder != null;
    }
 
    /// <summary>
    /// Migrationses the folder exists.
    /// </summary>
    /// <returns></returns>
    private bool MigrationsFolderExists()
    {
        var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath();
 
        return Directory.Exists(Path.Combine(dbMigrationsProjectFolder, "Migrations"));
    }
 
    /// <summary>
    /// Adds the initial migration.
    /// </summary>
    /// <exception cref="System.Exception">Couldn't run ABP CLI...</exception>
    private void AddInitialMigration()
    {
        _logger.LogDebug("Creating initial migration...");
 
        string argumentPrefix;
        string fileName;
 
        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            argumentPrefix = "-c";
            fileName = "/bin/bash";
        }
        else
        {
            argumentPrefix = "/C";
            fileName = "cmd.exe";
        }
 
        var procStartInfo = new ProcessStartInfo(fileName,
            $"{argumentPrefix} \"abp create-migration-and-run-migrator \"{GetEntityFrameworkCoreProjectFolderPath()}\"\""
        );
 
        try
        {
            Process.Start(procStartInfo);
        }
        catch (Exception)
        {
            throw new Exception("Couldn't run ABP CLI...");
        }
    }
 
    /// <summary>
    /// Gets the entity framework core project folder path.
    /// </summary>
    /// <returns></returns>
    /// <exception cref="System.Exception">Solution folder not found!</exception>
    private string GetEntityFrameworkCoreProjectFolderPath()
    {
        var slnDirectoryPath = GetSolutionDirectoryPath();
 
        if (slnDirectoryPath == null)
        {
            throw new Exception("Solution folder not found!");
        }
 
        var srcDirectoryPath = Path.Combine(slnDirectoryPath, "src");
 
        return Directory.GetDirectories(srcDirectoryPath)
            .FirstOrDefault(d => d.EndsWith(".EntityFrameworkCore"));
    }
 
    /// <summary>
    /// Gets the solution directory path.
    /// </summary>
    /// <returns></returns>
    private string GetSolutionDirectoryPath()
    {
        var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
 
        while (Directory.GetParent(currentDirectory.FullName) != null)
        {
            currentDirectory = Directory.GetParent(currentDirectory.FullName);
 
            if (Directory.GetFiles(currentDirectory.FullName).FirstOrDefault(f => f.EndsWith(".sln")) != null)
            {
                return currentDirectory.FullName;
            }
        }
 
        return null;
    }
}