Anwenden von Migrationen

Nachdem Ihre Migrationen hinzugefügt wurden, müssen sie bereitgestellt und auf Ihre Datenbanken angewendet werden. Hierfür gibt es verschiedene Strategien, wobei einige eher für Produktionsumgebungen und andere für den Entwicklungslebenszyklus besser geeignet sind.

Note

Was auch immer Ihre Bereitstellungsstrategie ist, überprüfen Sie immer die generierten Migrationen, und testen Sie diese vor der Anwendung auf eine Produktionsdatenbank. Eine Migration kann eine Spalte löschen, wenn beabsichtigt war, sie umzubenennen, oder sie kann aus verschiedenen Gründen fehlschlagen, wenn sie auf eine Datenbank angewendet wird.

Auswählen einer Bereitstellungsstrategie

Verwenden Sie für die automatisierte Bereitstellung ein Migrationsbundle. Ein Bündel ist ein Bereitstellungsartefakt, das in CI generiert und später ohne das .NET SDK, die EF Core-Tools oder den Quellcode der Anwendung ausgeführt werden kann. Verwenden Sie stattdessen ein SQL-Skript , wenn die SQL überprüft, geändert, archiviert oder an eine DBA übergeben werden muss, bevor sie angewendet wird.

Bei der lokalen Entwicklung dotnet ef database update ist dies in Update-Database der Regel die einfachste Option. Zielprojekte sollten die Integration von Aspire EF Core-Migrationen verwenden, um die lokale Migrationsausführung zu koordinieren und Bündel oder Skripts zu veröffentlichen.

Strategy Empfohlene Verwendung Überprüfen von SQL vor der Ausführung Erfordert SDK und Quelle zur Ausführung Verwendet EF-Migrationssperre Führt EF-Seeding-Delegaten aus.
SQL-Skript DBA-kontrollierte oder review-gated-Bereitstellung Yes No No No
Migrationspaket Automatisierte Bereitstellung No No Yes Yes
EF-Befehlszeilentools Lokale Entwicklung und Tests No Yes Yes Yes
Laufzeitmigration Anwendungen, die Startmigrations-Tradeoffs akzeptieren No No Yes Yes

EF Core 9 und höher verwenden die Migrationssperre. Synchrone Vorgänge und Aufrufen von UseSeedingTools ; asynchrone Vorgänge werden aufgerufen UseAsyncSeeding.

Verwenden Sie eine separate Identität für die Bereitstellung, die über die Berechtigung zum Ändern des Schemas verfügt. Die von der Anwendung zur Laufzeit verwendete Identität sollte normalerweise nur über die Berechtigungen verfügen, die die Anwendung zum Lesen und Schreiben von Daten benötigt.

SQL-Skripts

SQL-Skripts werden empfohlen, wenn für den Bereitstellungsprozess die generierte SQL vor der Ausführung überprüft oder geändert werden muss. Diese Strategie hat u. a. folgende Vorteile:

  • SQL-Skripts können auf Richtigkeit überprüft werden. Dies ist wichtig, da das Ändern von Schemas in Produktionsdatenbanken ein potenziell gefährlicher Vorgang ist, der zu Datenverlust führen kann.
  • In einigen Fällen können die Skripts so angepasst werden, dass sie den spezifischen Anforderungen einer Produktionsdatenbank entsprechen.
  • SQL-Skripts können in Verbindung mit einer Bereitstellungstechnologie verwendet und sogar als Teil Ihres CI-Prozesses generiert werden.
  • SQL-Skripts können für einen Datenbankadministrator bereitgestellt und separat verwaltet und archiviert werden.

Grundlegende Verwendung

Das Folgende generiert ein SQL-Skript von einer leeren Datenbank zur neuesten Migration:

dotnet ef migrations script

Standardmäßig schreibt der Befehl das Skript in die Standardausgabe. Verwenden Sie --output (oder -o) zum Erstellen eines Bereitstellungsartefaktes mit einem vorhersagbaren Namen:

dotnet ef migrations script --idempotent --output artifacts/migrations.sql

Mit „from“ („to“ wird impliziert)

Das Folgende generiert ein SQL-Skript aus der angegebenen Migration zur neuesten Migration.

dotnet ef migrations script AddNewTables

Mit „von“ und „bis“

Das Folgende generiert ein SQL-Skript aus der angegebenen from-Migration zur angegebenen to-Migration.

dotnet ef migrations script AddNewTables AddAuditTable

Sie können ein from verwenden, das aktueller ist als to, um ein Rollbackskript zu generieren.

Warning

Bitte achten Sie auf mögliche Datenverlustszenarios.

Die Skriptgenerierung akzeptiert die folgenden zwei Argumente, um anzugeben, welcher Migrationsbereich generiert werden soll:

  • Die from-Migration sollte die letzte Migration sein, die vor der Skriptausführung für die Datenbank durchgeführt wurde. Wenn keine Migrationen durchgeführt wurden, geben Sie 0 an (dies ist die Standardeinstellung).
  • Die to-Migration ist die letzte Migration, die nach der Skriptausführung für die Datenbank durchgeführt wurde. Dies ist standardmäßig die letzte Migration in Ihrem Projekt.

Migrationsskripts aktualisieren eine vorhandene Datenbank. Stellen Sie die Datenbank selbst über Ihren Infrastrukturbereitstellungs- oder Datenbankverwaltungsprozess bereit, bevor Sie das Skript anwenden. Die Datenbankerstellung erfordert in der Regel eine andere Verbindung, erhöhte Berechtigungen und eine anbieterspezifische Konfiguration.

Idempotente SQL-Skripts

Die oben generierten SQL-Skripts können nur angewendet werden, um Ihr Schema von einer Migration in eine andere zu ändern. Es liegt in Ihrer Verantwortung, das Skript angemessen und nur auf Datenbanken im richtigen Migrationszustand anzuwenden. EF Core unterstützt auch das Generieren von idempotenten Skripts, die intern überprüfen, welche Migrationen bereits angewendet wurden (über die Migrationsverlaufstabelle), und nur die fehlenden Skripts anwenden. Dies ist hilfreich, wenn Sie nicht genau wissen, welches die letzte auf die Datenbank angewendete Migration war, oder wenn Sie in mehrere Datenbanken bereitstellen, die sich jeweils in unterschiedlichen Migrationen befinden können.

Die Unterstützung von Idempotent-Skripts hängt vom Datenbankanbieter ab. Beispielsweise unterstützt SQLite derzeit das Generieren von idempotenten Migrationsskripts nicht.

Das Folgende generiert idempotente Migrationen:

dotnet ef migrations script --idempotent

Befehlszeilentools

Die EF-Befehlszeilentools können verwendet werden, um Migrationen auf eine Datenbank anzuwenden. Während dieser Ansatz für die lokale Entwicklung und das Testen von Migrationen produktiv ist, ist er für die Verwaltung von Produktionsdatenbanken nicht ideal:

  • Die SQL-Befehle werden direkt vom Tool angewendet, ohne dem Entwickler die Möglichkeit zu geben, sie zu überprüfen oder zu ändern. Dies kann in einer Produktionsumgebung gefährlich sein.
  • Das .NET SDK und das EF-Tool müssen auf Produktionsservern installiert sein und benötigen den Quellcode des Projekts.

Das Folgende aktualisiert Ihre Datenbank auf die neueste Migration:

dotnet ef database update

Das Folgende aktualisiert Ihre Datenbank auf eine angegebene Migration:

dotnet ef database update AddNewTables

Beachten Sie, dass dies auch zum Ausführen eines Rollbacks auf eine frühere Migration verwendet werden kann.

Warning

Bitte achten Sie auf mögliche Datenverlustszenarios.

Weitere Informationen zum Anwenden von Migrationen über die Befehlszeilentools finden Sie in der Referenz für EF Core-Tools.

Umgebung und Konfiguration

Die Tools führen Anwendungscode aus, um die DbContext. Anbieterauswahl, Verbindungszeichenfolgen und Modellkonfiguration können daher von der Anwendungsumgebung abhängen. Ef Core-Entwurfszeittools verwenden die Development Umgebung, wenn weder ASPNETCORE_ENVIRONMENT festgelegt noch DOTNET_ENVIRONMENT festgelegt wird.

Legen Sie die Umgebung beim Generieren eines Bereitstellungsartefaktes und beim Ausführen eines Bundles explizit fest. Beispiel in PowerShell:

$env:ASPNETCORE_ENVIRONMENT = 'Production'
dotnet ef migrations bundle --output artifacts\efbundle.exe
$env:ASPNETCORE_ENVIRONMENT = 'Production'
.\efbundle.exe --connection $env:DEPLOYMENT_CONNECTION_STRING

Oder in einer POSIX-kompatiblen Shell:

ASPNETCORE_ENVIRONMENT=Production \
    dotnet ef migrations bundle --output artifacts/efbundle

ASPNETCORE_ENVIRONMENT=Production \
    ./efbundle --connection "$DEPLOYMENT_CONNECTION_STRING"

Dadurch wird auch verhindert, dass ein Bündel die Geheimschlüssel der Entwicklungsbenutzer unerwartet lädt. Eine sicherere Standardumgebung für Bundles wird von dotnet/efcore#36188 nachverfolgt. Die Umgebungsauswahl in der Visual Studio Veröffentlichungsoberfläche wird von dotnet/efcore#11950 nachverfolgt.

Speichern Sie keine Produktionsverbindungszeichenfolgen in der Quellcodeverwaltung, oder betten Sie sie in das Bundle ein. Stellen Sie die Bereitstellungsverbindung aus dem geheimen Speicher des Bereitstellungssystems bereit. Die Bereitstellungsidentität sollte über Schemaberechtigungen verfügen; die normale Anwendungsidentität sollte in der Regel nicht verwendet werden.

Bundles

Migrationsbündel sind ausführbare Einzeldateien, die zum Anwenden von Migrationen auf eine Datenbank verwendet werden können. Sie beheben einige der Mängel des SQL-Skripts und der Befehlszeilentools:

  • Das Ausführen von SQL-Skripts erfordert zusätzliche Tools.
  • Das Transaktionshandling und das Verhalten für „Weiterfahren bei Fehler“ dieser Tools sind inkonsistent und manchmal unerwartet. Dies kann Ihre Datenbank in einem nicht definierten Zustand belassen, wenn beim Anwenden von Migrationen ein Fehler auftritt.
  • Bündel können als Teil Ihres CI-Prozesses generiert und später im Rahmen Ihres Bereitstellungsprozesses problemlos ausgeführt werden.
  • Bündel können ohne Installation des .NET SDK- oder EF-Tools (oder sogar der .NET Runtime, wenn sie eigenständig sind) ausgeführt werden, und sie erfordern nicht den Quellcode des Projekts.
  • Bündel verwenden die Migrationssperre von EF Core und führen die konfigurierte UseSeeding Logik aus.

Im Gegensatz zu einem SQL-Skript bietet ein Bündel derzeit keine Möglichkeit zum Überprüfen der SQL-Datei, die es ausführt oder die darin enthaltenen Migrationen auflistet. Wenn ihre Bereitstellung SQL-Überprüfung erfordert, generieren Sie stattdessen ein Skript. Paketüberprüfungsverbesserungen werden von dotnet/efcore#25872 nachverfolgt.

Das Folgende generiert ein Bündel:

dotnet ef migrations bundle --output artifacts/efbundle

Das Folgende generiert ein eigenständiges Bündel für Linux:

dotnet ef migrations bundle --self-contained --target-runtime linux-x64 --output artifacts/efbundle

Weitere Informationen zum Erstellen von Bündeln finden Sie in der Referenz für EF Core-Tools.

efbundle

Die resultierende ausführbare Datei erhält standardmäßig den Namen efbundle. Sie kann verwendet werden, um die Datenbank auf die neueste Migration zu aktualisieren. Es ist gleichbedeutend mit der Ausführung von dotnet ef database update oder Update-Database.

Arguments:

Argument Description
<MIGRATION> Die Zielmigration. Wenn „0“ ist, werden alle Migrationen rückgängig gemacht. Standard ist die letzte Migration.

Options:

Option Short Description
--connection <CONNECTION> Die Verbindungszeichenfolge zur Datenbank. Der Standard ist die in AddDbContext oder OnConfiguring angegebene.
--verbose -v Zeigt eine ausführliche Ausgabe an.
--no-color Färben Sie die Ausgabe nicht.
--prefix-output Stellen Sie der Ausgabe eine Ebene voran.

Im folgenden Beispiel werden Migrationen auf eine lokale SQL Server Instanz mit dem angegebenen Benutzernamen und den angegebenen Anmeldeinformationen angewendet:

.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password={;'$Credential;'here'}'

Wenn Sie die Datenbank zurücksetzen möchten, übergeben Sie die Migration, die weiterhin angewendet werden soll. Durch Übergeben 0 werden alle Migrationen wiederhergestellt:

.\efbundle.exe PreviousMigration --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;Integrated Security=True'
.\efbundle.exe 0 --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;Integrated Security=True'

Warning

Ein Rollback führt die Down Vorgänge jeder Migration neuer als das Ziel aus und kann zu Datenverlust führen. Überprüfen und testen Sie das Rollbackverhalten, bevor Sie es für Produktionsdaten verwenden.

Konfigurierter Seedingcode wird nach einem Downgrade ausgeführt. Es muss das Schema der Zielmigration tolerieren, einschließlich eines fehlenden Anwendungsschemas, wenn das Ziel ist 0.

Warning

Wenn die Kontextkonfiguration gelesen wird, kopieren Sie die erforderlichen Einstellungsdateien appsettings.jsonzusammen mit dem Bundle. Konfigurationsdateien werden aus dem Ausführungsverzeichnis des Bundles aufgelöst. Legen Sie keine Produktionsgeheimnisse in diese Dateien ein; Stellen Sie sie über eine sichere Konfigurationsquelle oder die --connection Option bereit.

Container- und Bereitstellungsaufträge

Generieren Sie das Bundle während des Builds, und führen Sie es als einmaligen Bereitstellungsauftrag aus, nachdem die Datenbank fehlerfrei ist. Installieren Sie das SDK nicht, oder führen dotnet ef Sie es im Anwendungsimage aus, und führen Sie nicht jedes Anwendungsreplikat Migrationen von seinem Einstiegspunkt aus. Konfigurieren Sie die Bereitstellungsplattform, um den Migrationscontainer nach dem erfolgreichen Beenden nicht neu zu starten.

Für Aspire-Anwendungen AddEFMigrations können Migrationen während der lokalen Entwicklung koordiniert werden. Während der Veröffentlichung PublishAsMigrationBundle kann ein Bündel oder ein Containerimage ausgegeben und PublishAsMigrationScript ein SQL-Skript ausgegeben werden. Siehe Anwenden von EF Core-Migrationen in Aspire für die Konfiguration eines einmaligen Auftrags für Azure Container Apps, Docker Compose und Kubernetes.

Das Migrationsbundlebeispiel veranschaulicht zwei SQLite-Migrationen, idempotent Seeding, Forward Application und Rollback-safe Seeding.

Beispiel für ein Migrationspaket

Ein Bundle muss Migrationen enthalten. Diese werden mittels dotnet ef migrations add erstellt, wie in Erstellen Ihrer ersten Migration beschrieben. Nachdem Sie die Migrationen für die Bereitstellung vorbereitet haben, erstellen Sie mithilfe von dotnet ef migrations bundle ein Bundle. Beispiel:

PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>

Die Ausgabe ist eine ausführbare Datei, die für Ihr Zielbetriebssystem geeignet ist. In meinem Fall ist dies Windows x64, daher wird eine efbundle.exe-Datei in meinem lokalen Ordner abgelegt. Beim Ausführen dieser ausführbaren Datei werden die darin enthaltenen Migrationen angewendet:

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903083845_MyMigration'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Wie mit dotnet ef database update oder Update-Database werden Migrationen nur dann auf die Datenbank angewendet, wenn sie noch nicht angewendet wurden. Wenn Sie z. B. dasselbe Bundle erneut ausführen, passiert nichts, da es keine neuen Migrationen gibt, die angewendet werden müssen.

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
No migrations were applied. The database is already up to date.
Done.
PS C:\local\AllTogetherNow\SixOh>

Wenn jedoch Änderungen am Modell vorgenommen werden und mit dotnet ef migrations add weitere Migrationen generiert werden, können diese in einer neuen ausführbaren Datei gebündelt werden, die übernommen werden kann. Beispiel:

PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add SecondMigration
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add Number3
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle --force
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>

Tip

Die --force-Option kann verwendet werden, um das vorhandene Bündel mit einem neuen zu überschreiben.

Beim Ausführen dieses neuen Bundle werden die folgenden beiden neuen Migrationen auf die Datenbank angewendet:

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Standardmäßig verwendet das Bundle die Verbindungszeichenfolge aus der Konfiguration Ihrer Anwendung. Eine andere Datenbank kann jedoch migriert werden, indem die Verbindungszeichenfolge in der Befehlszeile übergeben wird. Beispiel:

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe --connection "Data Source=(LocalDb)\MSSQLLocalDB;Database=SixOhProduction"
Applying migration '20210903083845_MyMigration'.
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Note

Diesmal wurden alle drei Migrationen angewendet, da noch keine davon auf die Produktionsdatenbank angewendet wurde.


Anwenden von Migrationen zur Laufzeit

Es ist möglich, dass die Anwendung selbst Migrationen programmgesteuert anwendet, in der Regel während des Starts. EF Core 9 und höher schützen die Migrationsausführung mit einer datenbankweiten Sperre, sodass dies für Anwendungen akzeptabel sein kann, die einfache Bereitstellung bevorzugen und das Startmigrationsverhalten tolerieren können. Ein separater Migrationsbereitstellungsschritt wird immer noch bevorzugt, wenn Überprüfung, Anmeldeinformationen mit geringsten Berechtigungen, koordiniertes Rollout oder hohe Verfügbarkeit wichtig sind.

Berücksichtigen Sie die folgenden Kompromisse:

  • Vor der Version 9 von EF gilt: Wenn mehrere Instanzen Ihrer Anwendung ausgeführt werden, können beide Anwendungen versuchen, die Migration gleichzeitig anzuwenden, was zu einem Fehler (oder schlimmer noch: zu Datenbeschädigungen) führen kann.
  • Ähnlich verhält es sich, wenn eine Anwendung auf die Datenbank zugreift, während eine andere Anwendung sie migriert, dies kann zu schwerwiegenden Problemen führen.
  • Die Anwendung muss über erhöhten Zugriff verfügen, um das Datenbankschema zu ändern. In der Regel ist es eine gute Praxis, die Datenbankberechtigungen der Anwendung in der Produktion einzuschränken.
  • Es ist wichtig, im Falle eines Problems ein Rollback einer angewendeten Migration durchführen zu können. Die anderen Strategien bieten dies einfach und sofort einsatzbereit an.
  • Die SQL-Befehle werden direkt vom Programm angewendet, ohne dem Entwickler die Möglichkeit zu geben, sie zu prüfen oder zu ändern. Dies kann in einer Produktionsumgebung gefährlich sein.

Rufen Sie context.Database.MigrateAsync() auf, um Migrationen programmgesteuert anzuwenden. Eine typische ASP.NET Anwendung kann z. B. folgende Aktionen ausführen:

public static async Task Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        await db.Database.MigrateAsync();
    }

    host.Run();
}

Beachten Sie, dass MigrateAsync() auf dem IMigrator-Dienst basiert, der für erweiterte Szenarien verwendet werden kann. Verwenden Sie myDbContext.GetInfrastructure().GetService<IMigrator>(), um darauf zugreifen.

Warning

  • Überlegen Sie sorgfältig, bevor Sie diesen Ansatz in der Produktion anwenden. Bevorzugen Sie ein Migrationspaket für die Automatisierung oder ein SQL-Skript, wenn Überprüfung und Genehmigung erforderlich sind.
  • Rufen Sie EnsureCreatedAsync() nicht vor MigrateAsync() auf. EnsureCreatedAsync() umgeht Migrationen zum Erstellen von Schemas, was dazu führt, dass MigrateAsync() fehlerhaft ist.

Migrationssperre

Beginnend mit EF Core 9 erwerben MigrateAsync und Migrate automatisch eine datenbankweite Sperre, bevor Migrationen angewendet werden. Dadurch wird vor Datenbankbeschädigungen geschützt, die sich aus mehreren Anwendungsinstanzen ergeben können, die gleichzeitig Migrationen ausführen. Dies ist ein häufiges Szenario beim Anwenden von Migrationen zur Laufzeit. Die Sperre wird für die Dauer der Migrationsausführung, einschließlich des Initialisierungscodes, gehalten und automatisch freigegeben, wenn der Vorgang abgeschlossen ist.

Die Migrationssperre gilt, wenn Migrationen mit einer der folgenden Methoden angewendet werden:

SQL-Skripts sind von der Migrationssperre nicht betroffen, da sie außerhalb von EF Core angewendet werden.

Note

Ab EF Core 9 wird beim Aufrufen von Migrate() oder MigrateAsync() eine Ausnahme ausgelöst, wenn das Modell im Vergleich zur letzten Migration ausstehende Änderungen aufweist (Warnungsereignis-ID RelationalEventId.PendingModelChangesWarning). Um diese Bedingung vor der Bereitstellung zu erkennen, verwenden Sie den dotnet ef migrations has-pending-model-changes Befehl in Ihrer CI/CD-Pipeline. Die Warnung kann bei Bedarf über ConfigureWarnings (Ignorieren RelationalEventId.PendingModelChangesWarning) unterdrückt werden, dies wird jedoch in Produktionsszenarien im Allgemeinen nicht empfohlen. Weitere Informationen finden Sie in der aktuellen Änderungsnotiz .

Warning

Der Sperrmechanismus variiert erheblich zwischen Datenbankanbietern und kann anbieterspezifische Probleme umfassen. Beispielsweise verwendet der SQLite-Anbieter eine Sperrtabelle, die abgebrochen werden kann , wenn der Prozess unerwartet beendet wird. Weitere Informationen finden Sie in der Dokumentation Ihres Anbieters.

Einschränkungen