单层解决方案:数据库迁移器
与分层解决方案模板不同,单层解决方案模板不包含独立的数据库迁移器项目。取而代之的是,主应用程序项目负责处理数据库迁移和种子数据操作。此模板中不包含 *.DbMigrator 项目。要管理数据库迁移和种子数据,您可以使用根目录下的 migrate-database.ps1 脚本,或在主应用程序项目目录中运行 dotnet run --migrate-database 命令。
迁移完成后,控制台会显示一条消息。您可以通过检查数据库来验证迁移是否成功。
数据库迁移服务
在项目的 Data 文件夹下,BookstoreDbMigrationService 类负责数据库迁移和种子数据操作。当应用程序以 --migrate-database 参数启动时,Program 类会调用 MigrateAsync 方法来迁移数据库。
首先,它会检查数据库是否已创建,并应用待处理的迁移。然后,通过 SeedAsync 方法填充初始数据。
public async Task MigrateAsync()
{
var initialMigrationAdded = AddInitialMigrationIfNotExist();
if (initialMigrationAdded)
{
return;
}
Logger.LogInformation("开始数据库迁移...");
await MigrateDatabaseSchemaAsync();
await SeedDataAsync();
Logger.LogInformation($"成功完成主机数据库迁移。");
var tenants = await _tenantRepository.GetListAsync(includeDetails: true);
var migratedDatabaseSchemas = new HashSet<string>();
foreach (var tenant in tenants)
{
using (_currentTenant.Change(tenant.Id))
{
if (tenant.ConnectionStrings.Any())
{
var tenantConnectionStrings = tenant.ConnectionStrings
.Select(x => x.Value)
.ToList();
if (!migratedDatabaseSchemas.IsSupersetOf(tenantConnectionStrings))
{
await MigrateDatabaseSchemaAsync(tenant);
migratedDatabaseSchemas.AddIfNotContains(tenantConnectionStrings);
}
}
await SeedDataAsync(tenant);
}
Logger.LogInformation($"成功完成 {tenant.Name} 租户数据库迁移。");
}
Logger.LogInformation("成功完成所有数据库迁移。");
Logger.LogInformation("您可以安全地结束此进程...");
}
BookstoreDbSchemaMigrator 类在 MigrateDatabaseSchemaAsync 方法中用于数据库迁移过程,负责将迁移应用到数据库。
public class BookstoreDbSchemaMigrator : ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public BookstoreDbSchemaMigrator(
IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task MigrateAsync()
{
/* 我们特意从 IServiceProvider 解析 BookstoreDbContext
* (而不是直接注入)
* 以正确获取当前作用域中当前租户的连接字符串。
*/
await _serviceProvider
.GetRequiredService<BookstoreDbContext>()
.Database
.MigrateAsync();
}
}
抠丁客



