Kör MigrateAsync() på start? Du ger din app databas ägare rättigheter och hoppas att ingenting går fel. Det finns ett bättre sätt - EF migration buntar låter dig köra migreringar som en kontrollerad CI steg, hålla din produktions app säker. Men här är grejen: ibland är "fel" sätt faktiskt bra. Låt oss undersöka när man ska använda varje strategi.
Officiella dokument: Översikt över migrationer | Att tillämpa migreringar | Bundor
Den här bloggen använder MigrateAsync() Det är därför det är okej för mig, och varför det förmodligen inte är för dig.
I min Program.cs Fil Jag har följande:
using (var scope = app.Services.CreateScope())
{
var blogContext = scope.ServiceProvider.GetRequiredService<IMostlylucidDBContext>();
await blogContext.Database.MigrateAsync();
}
MigrateAsync() gäller pågående migreringar och skapar databasen vid behov. Enkelt - men problematiskt:
db_owner Du gav din runtime app nycklarna till att släppa bord.Varför jag kommer undan med det: offentliga data, enda Docker nätverk, personliga projekt. Det kan du nog inte.
En EF bunt är en fristående körbar som innehåller dina kompilerade migreringar. dotnet ef database update förpackade i ett fristående .exe.
Varför buntar vinner:
db_owner; endast CI löpare gör, endast under utplaceringAnmärkning: För säkerhet i produktionsledet, användning Hanterad identitet Men buntar är fortfarande ett stort steg upp från runtime migreringar.
- 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 }}
Bunten läser anslutningssträngar från miljövariabler och tillämpar väntande migreringar. Redan tillämpad? Det bara avslutar framgångsrikt.
Användningsfall: Test före CI, DBA-avlämning (självförsörjande exe, ingen SDK behövs), iscensättningar, felsökning med --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
Fångar syntaxfel, begränsningsbrott, FK-problem - alla före CI eller tillverkning.
Bundelgenerationen är långsam - 30 sekunder på stora projekt. generera inte på varje byggnad.
Om du verkligen vill ha automatisk generation, lägg till ett MSBuild-mål:
<Target Name="BuildMigrationBundle">
<Exec Command="dotnet ef migrations bundle --output $(OutputPath)efbundle.exe --force" />
</Target>
Därefter gäller följande: dotnet build -t:BuildMigrationBundle
Bäst av båda världarna: bekvämlighet lokalt, säkerhet i produktionen.
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
Generera vanlig SQL istället för en körbar. Bra för DBA översyn och befintliga förändringshanteringsprocesser.
# 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
Förmåner: Full synlighet, alla SQL-klienter kan köra den, versionskontroll vänliga, DBA-godkännande arbetsflöden.
Minus: Ingen automatisk spårning (använd --idempotent), manuell körning, potentiell drift om skript ändras.
Se också officiella dokument om SQL- skript.
- 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
AVS-staterna är Tillståndsbaserad inte Migrationsbaserad. Du definierar önskat schema, och SqlPackage diffs det mot målet databasen.
SqlPackage.exe /Action:Publish /SourceFile:MyDatabase.dacpac /TargetConnectionString:"..."
Förmåner: Schema som kod, automatisk diff-generering, hanterar allt (tabeller, vyer, SPs, index), företagsverktyg.
Minus: Endast SQL Server, schema på två ställen (EF-modeller + SQL-projekt), diff-motorn gör tvivelaktiga val, kolumn omnamn ser ut som drop+add.
Se också SqlPackage- dokument.
Tillvägagångssätt på bästa sätt för att kräva .NET på Auto-tracks Tillämpas DBA Friendly på plattform DB
|----------|----------|---------------|---------------------|--------------|-------------------|
| MigrateAsync() Dev/små projekt Ja (körtid) Ja Nej Ja Ja
på EF-bundlar på CI/CD-rörledningar på Nej (självförsörjande) på något sätt Ja
på SQL-skript, DBA-kontrollerade miljöer, Nej, med --idempotent "Ja, ja, ja, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej, nej!
DAVSAC på SQL Server-företag Nej på plats Ja (state-based) på plats Ja Nej
Migration fungerar lokalt men inte inom KI? Kontrollera att du använde båda filerna:
20231115_AddUserTable.cs - Migrationskoden20231115_AddUserTable.Designer.cs - ModellögonblicksbildSaknar Designer-filen = tyst fel.
dotnet ef migrations bundle --context BlogDbContext --output blog-migrations.exe
dotnet ef migrations bundle --context IdentityDbContext --output identity-migrations.exe
--connection argumenteringappsettings.jsonAnvänd miljövariabler i KI.
EF- verktyg behöver för att direktiate din DbContext. Om din DbContext är i ett separat projekt eller har komplexa start, genomföra 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);
}
}
Använd när: DbContext i separat projekt, komplex start, behöver användarhemligheter för design-tid.
Vanliga frågor och motgångar har jag fått.
dotnet ef database update I CI?"Täckt ovan, men den korta versionen: buntar är bärbara artefakter. Din distribution steg behöver inte EF CLI, källkod, eller design-tidsupplösning. Samma bunt körs i test, iscensättning, och prod - noll drift.
Om du är solo är data allmänt tillgänglig och explosionsradie är låg. MigrateAsync() är bra. Men när du lägger till en andra utvecklare, känslig data, eller flera miljöer, buntar betalar för sig själva.
EF gör inte automatiska upprullningar.
Down() migration och köra den (men du måste ha skrivit den)För kritiska system: testa migreringar mot en databasklon först.
Ja. Bundle + init behållare är ett fast mönster:
initContainers:
- name: migrate
image: myapp:latest
command: ["./efbundle.exe"]
env:
- name: ConnectionStrings__Default
valueFrom:
secretKeyRef:
name: db-secrets
key: connection-string
App behållare väntar på init att slutföra.
De fungerar bra. EF buntar är EF-nativ lösning, men FluentMigrator och DbUp nyckelskillnaden: de är migrationsspecifika verktyg, medan EF-paket kommer från din befintliga EF-modell.
Användning --idempotent skript:
dotnet ef migrations script --idempotent --output migrations.sql
DBA granskar och godkänner. Sedan antingen:
Det är en utplaceringsstrategi, inte en migrationsfråga.
Bundles löser inte det här - de gör bara steg 3 mer förutsägbara.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.