Skip to content
Merged

Dev #2799

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,10 @@ Once you've configured your connection strings via `appsettings.secrets.json` (o
dotnet run
```

Migration history flattening is disabled by default. To reconcile databases that still
contain migration ids from the removed migration set, run the migrator once with
`Database__FlattenMigrations=true` (or set `Database:FlattenMigrations` to `true` in
`appsettings.secrets.json`). Do not leave this enabled for normal migration runs: it
deletes migration history rows that were added after the flattened `Initial` migration.

Or run it from Visual Studio by setting `Unity.GrantManager.DbMigrator` as the startup project.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres;",
"Onboarding": "Host=localhost;port=5432;Database=Onboarding;Username=postgres;"
},
"Database": {
"FlattenMigrations": false
},
"StringEncryption": {
"DefaultPassPhrase": "g2IuZx7PwXDvCmlW"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace Unity.GrantManager.EntityFrameworkCore;
public class EntityFrameworkCoreGrantManagerDbSchemaMigrator(
IServiceProvider serviceProvider,
IStringEncryptionService encryptionService,
IConfiguration configuration,
ILogger<EntityFrameworkCoreGrantManagerDbSchemaMigrator> logger)
: IGrantManagerDbSchemaMigrator, ITransientDependency
{
Expand All @@ -30,20 +31,18 @@ public class EntityFrameworkCoreGrantManagerDbSchemaMigrator(
* "Initial" and would make Database.MigrateAsync() below try to re-run Initial's
* CreateTable operations against a schema that already has them.
*
* ReconcileMigrationHistoryAsync resets history to just the Initial row *before*
* MigrateAsync() is called, so EF sees it as already applied and skips it. Brand
* new databases (including newly provisioned tenants) have an empty or nonexistent
* history table at this point, so the reconciliation is a no-op and MigrateAsync()
* runs Initial for real to build the schema. Safe to run unconditionally on every
* migrator invocation, forever - after the first run per database, history only
* ever contains the Initial row so the guard clause never fires again.
* ReconcileMigrationHistoryAsync resets history to just the Initial row before
* MigrateAsync() is called, so EF sees it as already applied and skips it. This is
* an explicit one-time operation because running it during normal migration startup
* would also remove legitimate migrations added after the flattening.
*/
private const string HostInitialMigrationId = "20260722193713_Initial";
private const string TenantInitialMigrationId = "20260721203242_Initial";
private const string EfCoreProductVersion = "10.0.3";

private readonly IServiceProvider _serviceProvider = serviceProvider;
private readonly IStringEncryptionService _encryptionService = encryptionService;
private readonly bool _flattenMigrations = configuration.GetValue<bool>("Database:FlattenMigrations");
private readonly ILogger<EntityFrameworkCoreGrantManagerDbSchemaMigrator> _logger = logger;

public async Task MigrateAsync(Tenant? tenant)
Expand Down Expand Up @@ -104,7 +103,10 @@ public async Task MigrateAsync(Tenant? tenant)
await tenantDb.ExecuteSqlRawAsync(
tenantDb.GetService<IHistoryRepository>().GetCreateIfNotExistsScript());

await ReconcileMigrationHistoryAsync(tenantDb, TenantInitialMigrationId);
if (_flattenMigrations)
{
await ReconcileMigrationHistoryAsync(tenantDb, TenantInitialMigrationId);
}

// Run migrations as admin against the tenant database
await MigrateAndLogAsync(tenantDb, $"tenant:{tenant.Name}");
Expand Down Expand Up @@ -162,7 +164,10 @@ the correct one. */
await hostDb.ExecuteSqlRawAsync(
hostDb.GetService<IHistoryRepository>().GetCreateIfNotExistsScript());

await ReconcileMigrationHistoryAsync(hostDb, HostInitialMigrationId);
if (_flattenMigrations)
{
await ReconcileMigrationHistoryAsync(hostDb, HostInitialMigrationId);
}

await MigrateAndLogAsync(hostDb, "host");
}
Expand Down
Loading