Vai al contenuto

Migrazioni EF Core

I plugin che persistono dati (Schulware, OdaOrg) gestiscono il proprio schema tramite le migrazioni EF Core.

Ogni plugin ha il proprio database

L'host dei plugin del backend fornisce al plugin una connection string dedicata tramite PluginServiceContext.ConnectionString - modifica la connection string dell'host in modo che il nome del database diventi schuly_plugin_<name>. Il plugin la collega al proprio DbContext:

csharp
services.AddDbContext<SchulwareDbContext>(o => o.UseNpgsql(context.ConnectionString));

Le migrazioni non toccano quindi mai il database Schuly principale; lo schema di ogni plugin è isolato.

Aggiungere una migrazione

sh
dotnet ef migrations add <Name> --project src/Schuly.Plugin.Schulware

(Sostituisci il percorso del progetto con quello del plugin su cui stai lavorando.) Questo scrive la migrazione nella cartella Data/Migrations/ del plugin e aggiorna lo snapshot del modello. Richiede lo strumento dotnet-ef - vedi setup/development.md.

Factory design-time

dotnet ef costruisce il DbContext in fase di design senza la pipeline DI a runtime, quindi ogni plugin fornisce una IDesignTimeDbContextFactory<T> accanto al proprio DbContext (ad es. Data/SchulwareDbContextFactory.cs). La connection string nella factory è un segnaposto usa e getta - le migrazioni hanno bisogno solo del modello, non di un database attivo:

csharp
internal sealed class SchulwareDbContextFactory : IDesignTimeDbContextFactory<SchulwareDbContext>
{
    public SchulwareDbContext CreateDbContext(string[] args) =>
        new(new DbContextOptionsBuilder<SchulwareDbContext>()
            .UseNpgsql("Host=localhost;Database=schulware_design;Username=postgres;Password=postgres")
            .Options);
}

Applicare le migrazioni a runtime, non EnsureCreated

Applica le migrazioni in sospeso da MigrateAsync:

csharp
public async Task MigrateAsync(IServiceProvider sp, CancellationToken ct = default)
{
    using var scope = sp.CreateScope();
    var db = scope.ServiceProvider.GetRequiredService<SchulwareDbContext>();
    await db.Database.MigrateAsync(ct);
}

Usa MigrateAsync(), mai EnsureCreatedAsync. EnsureCreatedAsync crea il database alla prima esecuzione, ma non fa nulla ai successivi cambi di schema, quindi aggiunte di colonne o indici non arriverebbero mai su un database esistente. MigrateAsync() crea il DB alla prima esecuzione e applica in seguito ogni delta di schema.