This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Sunday, 23 November 2025
Suoritetaan MigrateAsync() Startupissa? Annat sovellustietokannan omistajalle oikeudet ja toivot, että mikään ei mene pieleen. On olemassa parempi tapa - EF migration -nippujen avulla voit pyörittää muuttoliikkeitä kontrolloituna CI-askeleena ja pitää tuotantosovelluksesi turvallisena. Mutta joskus "väärä" tapa on itse asiassa hyvä. Tutkitaan, milloin kannattaa käyttää jokaista lähestymistapaa.
Viralliset dokumentit: Maahanmuuttoa koskeva yleiskatsaus | Muuttoliikkeiden soveltaminen | Punokset
Tämä blogi käyttää MigrateAsync() Startup - lähestymistapa, jota aion kieltää käyttämästä. Tämän vuoksi se sopii minulle, ja miksi se ei todennäköisesti ole sinulle.
Omassa Program.cs Minulla on seuraavat tiedot:
using (var scope = app.Services.CreateScope())
{
var blogContext = scope.ServiceProvider.GetRequiredService<IMostlylucidDBContext>();
await blogContext.Database.MigrateAsync();
}
MigrateAsync() soveltaa vireillä olevia siirtoja ja luo tarvittaessa tietokannan. Yksinkertainen - mutta ongelmallinen:
db_owner Annoit juuri aika-applikaatiollesi avaimet pudottaa pöytiä.Miksi pääsen pälkähästä: julkinen data, yksittäinen Docker-verkko, henkilökohtainen projekti. Et varmaankaan pysty.
EF-nippu on omatoiminen suoritin, joka sisältää kootut muuttoliikkeesi. dotnet ef database update pakataan itsenäiseksi .exe.
Miksi nippuja voittaa:
db_owner; vain CI-juoksijalla on, vain käyttöönoton aikanaHuomaa: Tuotantoluokan varmuuteen, käyttöön Hallittu henkilöllisyys Kytkentänarujen sijaan, mutta nippu on yhä merkittävä askel eteenpäin.
- name: Install EF Core tools
run: dotnet tool install --global dotnet-ef
- name: Add EF tools to PATH
run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH
- name: Generate EF migration bundle
run: |
dotnet ef migrations bundle \
--project ${{ env.WEB_PROJECT }} \
--output efbundle.exe \
--configuration ${{ env.BUILD_CONFIGURATION }} \
--runtime ${{ env.RUNTIME_IDENTIFIER }} \
--context AdminDbContext \
env:
AdminSite__ConnectionString: ${{ secrets.PROD_SQL_CONNECTIONSTRING }}
- name: Run EF migration bundle
run: |
./efbundle.exe
env:
AdminSite__ConnectionString: ${{ secrets.PROD_SQL_CONNECTIONSTRING }}
Nippu lukee yhteyden naruja ympäristömuuttujista ja soveltaa vireillä olevia muuttoliikkeitä. Jo käytössä? Se vain poistuu onnistuneesti.
Ei tiedonantajaa, haluatko testata ennen työntämistä? Rakenna nippuja paikallisesti.
Käyttötapaukset: Testaa ennen CI:n, DBA:n luovutusta (itse asiassa exe, ei SDK:ta tarvita), lavastusten käyttöönottoa, vianetsintää --verbose.
# Install EF CLI (once)
dotnet tool install --global dotnet-ef
# Basic bundle
dotnet ef migrations bundle \
--project Mostlylucid.DbContext \
--startup-project Mostlylucid \
--output efbundle.exe
# Self-contained (includes runtime - portable to machines without .NET)
dotnet ef migrations bundle \
--project Mostlylucid.DbContext \
--startup-project Mostlylucid \
--output efbundle.exe \
--self-contained
# Cross-platform (e.g., build on Windows, deploy to Linux)
dotnet ef migrations bundle \
--project Mostlylucid.DbContext \
--startup-project Mostlylucid \
--output efbundle \
--runtime linux-x64
# Using default connection string from appsettings.json
./efbundle.exe
# Override with a specific connection string
./efbundle.exe --connection "Host=localhost;Database=mostlylucid;Username=postgres;Password=secret"
# Using an environment variable (matches your config key)
$env:ConnectionStrings__DefaultConnection="Host=localhost;..." # PowerShell
export ConnectionStrings__DefaultConnection="Host=localhost;..." # Bash
./efbundle.exe
# See what migrations would be applied without running them
./efbundle.exe --dry-run
# Verbose output for debugging
./efbundle.exe --verbose
# Apply migrations up to a specific migration (useful for testing)
./efbundle.exe --target-migration "20231115_AddUserTable"
# Combine options
./efbundle.exe --verbose --dry-run
# 1. Create migration
dotnet ef migrations add AddNewFeature \
--project Mostlylucid.DbContext \
--startup-project Mostlylucid
# 2. Build bundle
dotnet ef migrations bundle \
--project Mostlylucid.DbContext \
--startup-project Mostlylucid \
--output efbundle.exe
# 3. Dry run first
./efbundle.exe --dry-run --verbose
# 4. Run for real
./efbundle.exe --verbose
# 5. Broken? Remove and retry
dotnet ef migrations remove \
--project Mostlylucid.DbContext \
--startup-project Mostlylucid
Nappaa syntaksivirheitä, rajoitusrikkomuksia, FK-asioita - kaikki ennen CI tai tuotanto.
Bundle-sukupolvi on hidas - 30 sekuntia isoissa projekteissa.
Jos todella haluat autogeneraatiota, lisää MSBuild-kohde:
<Target Name="BuildMigrationBundle">
<Exec Command="dotnet ef migrations bundle --output $(OutputPath)efbundle.exe --force" />
</Target>
Sitten: dotnet build -t:BuildMigrationBundle
Paras molemmista maailmoista: mukavuus paikallisesti, tuotannon turvallisuus.
if (builder.Environment.IsDevelopment())
{
using var scope = app.Services.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<IMostlylucidDBContext>();
await context.Database.MigrateAsync();
}
// Production: CI pipeline runs the bundle
Luo tavallinen SQL suoritettavan sijaan. Loistava DBA-arviointiin ja olemassa oleviin muutoshallintaprosesseihin.
# All migrations
dotnet ef migrations script --output migrations.sql
# Idempotent (safe to run multiple times) - USE THIS
dotnet ef migrations script --idempotent --output migrations.sql
# Range of migrations
dotnet ef migrations script FromMigration ToMigration --output migrations.sql
Plussat: Täysi näkyvyys, mikä tahansa SQL-asiakas voi ajaa sitä, versiohallinta ystävällinen, DBA-hyväksynnän työnkulku.
Miinukset: Ei automaattijäljitystä (käytä --idempotent), manuaalinen suoritus, mahdollinen drift, jos skriptejä muutetaan.
Katso viralliset dokumentit SQL-skripteistä.
- name: Generate and apply migrations
run: |
dotnet ef migrations script --idempotent --output migrations.sql
# SQL Server
sqlcmd -S ${{ secrets.DB_SERVER }} -d ${{ secrets.DB_NAME }} -i migrations.sql
# Or PostgreSQL
PGPASSWORD=${{ secrets.DB_PASSWORD }} psql -h ${{ secrets.DB_HOST }} -f migrations.sql
DACPAC-keskukset a valtiolähtöinen ei Muuttoliikkeeseen perustuvaMäärität halutun skeeman, ja SqlPackage vertaa sitä kohdetietokantaan.
SqlPackage.exe /Action:Publish /SourceFile:MyDatabase.dacpac /TargetConnectionString:"..."
Plussat: Schema koodina, automaattisena diff-sukupolvena, hoitaa kaiken (taulukot, näkymät, SP:t, indeksit), yritystyökalut.
Miinukset: Vain SQL Server, schema kahdessa paikassa (EF-mallit + SQL-projekti), diff-moottori tekee kyseenalaisia valintoja, sarake uudelleennimet näyttävät pudotus+lisältä.
Katso SqlPackage-dokumentit.
Autoraiteet Sovellettava DBA Friendly Cross-platform DB
|----------|----------|---------------|---------------------|--------------|-------------------|
| MigrateAsync() Kyllä, kyllä, kyllä, kyllä, kyllä
EF Bundles CI/CD-putkistot
SQL:n käsikirjoitukset DBA:n hallitsemissa ympäristöissä --idempotent Kyllä, kyllä, kyllä.
DACPAC, SQL Server enterprise Yes (valtiollinen) Kyllä
Muuttoliikkeet toimivat paikallisesti, mutta eivät tiedonantajana? Tarkista, että kirjoitit molemmat tiedostot:
20231115_AddUserTable.cs - Maahanmuuttokoodi20231115_AddUserTable.Designer.cs - MallikuvaDesigner-tiedoston puuttuminen = äänetön epäonnistuminen.
dotnet ef migrations bundle --context BlogDbContext --output blog-migrations.exe
dotnet ef migrations bundle --context IdentityDbContext --output identity-migrations.exe
--connection argumenttiappsettings.jsonKäytä ympäristömuuttujia CI:ssä.
Jos DbContext on erillisessä projektissa tai siinä on monimutkainen käynnistys, toteuta IDesignTimeDbContextFactory<T>:
public class AdminDbContextFactory : IDesignTimeDbContextFactory<AdminDbContext>
{
public AdminDbContext CreateDbContext(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true)
.AddEnvironmentVariables()
.AddUserSecrets<AdminDbContextFactory>()
.Build();
var connectionString = config["AdminSite:ConnectionString"]
?? throw new InvalidOperationException("Missing connection string");
var optionsBuilder = new DbContextOptionsBuilder<AdminDbContext>();
optionsBuilder.UseSqlServer(connectionString, sql => sql.CommandTimeout(120));
return new AdminDbContext(optionsBuilder.Options);
}
}
Käytä, kun: DbContext erillisessä projektissa, monimutkainen käynnistys, tarvitsee käyttäjäsalaisuuksia suunnitteluaikaan.
Olen saanut yleisiä kysymyksiä ja vastatoimia.
dotnet ef database update CI:ssä?"Katettu yllä, mutta lyhyt versio: niput ovat kannettavia esineitä. Käyttöönottovaihe ei tarvitse EF CLI:tä, lähdekoodia tai suunnitteluajan tarkkuutta. Sama nippu kulkee testissä, lavastuksessa ja prod - nolla-ajossa.
Jos olet yksin, data on julkista, ja räjähdyssäde on matala. MigrateAsync() Mutta heti kun lisäät toisen kehittäjän, arkaluonteisen datan tai useita ympäristöjä, nippu maksaa itsensä.
EF ei tee automaattikäännöksiä.
Down() Muuttoliike ja sen pyörittäminen (mutta sinun täytyy olla kirjoittanut se)Kriittisten järjestelmien osalta testataan ensin migraatiota tietokantakloonia vastaan.
Kyllä. Bundle + init -pakkaus on kiinteä kuvio:
initContainers:
- name: migrate
image: myapp:latest
command: ["./efbundle.exe"]
env:
- name: ConnectionStrings__Default
valueFrom:
secretKeyRef:
name: db-secrets
key: connection-string
Applikaattori odottaa, että se valmistuu.
Ne toimivat hyvin. EF-nippu on EF-natiivi ratkaisu, mutta FluentMigraattori sekä DbUp Avainero: ne ovat muuttoliikkeelle ominaisia työkaluja, kun taas EF-nippu on peräisin nykyisestä EF-mallistasi.
Käyttö --idempotent käsikirjoitukset:
dotnet ef migrations script --idempotent --output migrations.sql
DBA arvioi ja hyväksyy. Sitten joko:
Se on käyttöönottostrategiakysymys, ei maahanmuuttokysymys.
Bundlet eivät ratkaise tätä, ne vain tekevät vaiheesta 3 ennustettavamman.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.