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.

Hinweis

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 trennen, wenn es die Absicht war, sie umzubenennen, oder sie kann aus verschiedenen Gründen fehlschlagen, wenn sie auf eine Datenbank angewendet wird.

SQL-Skripts

Die empfohlene Möglichkeit zum Bereitstellen von Migrationen in einer Produktionsdatenbank ist das Generieren von SQL-Skripts. 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

Mit „from“ („to“ wird impliziert)

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

dotnet ef migrations script AddNewTables

Mit „from“ und „to“

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.

Warnung

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.

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.

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.

Hinweis

Jede Migration wird in ihrer eigenen Transaktion angewendet. Im GitHub-Issue #22616 finden Sie eine Erläuterung möglicher zukünftiger Verbesserungen in diesem Bereich.

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.

Warnung

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.

Bündel

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 ausgeführt werden, ohne das .NET-SDK oder das EF-Tool (oder sogar die .NET-Runtime, wenn eigenständig) zu installieren, und sie benötigen nicht den Quellcode des Projekts.

Das Folgende generiert ein Bündel:

dotnet ef migrations bundle

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

dotnet ef migrations bundle --self-contained -r linux-x64

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.

Argumente:

Argument Beschreibung
<MIGRATION> Die Zielmigration. Wenn „0“ werden alle Migrationen wiederhergestellt. Der Standardwert ist die letzte Migration.

Optionen:

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

Im folgenden Beispiel werden Migrationen auf eine lokale SQL Server-Instanz mithilfe des angegebenen Benutzernamens und Kennworts angewendet.

.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password=myPassword'

Warnung

Vergessen Sie nicht, appsettings.json zusammen mit Ihrem Bundle zu kopieren. Das Bundle basiert auf dem Vorhandensein von appsettings.json im Ausführungsverzeichnis.

Beispiel für ein Migrationsbündel

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, sodass eine efbundle.exe in meinem lokalen Ordner abgelegt wird. 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, wird es nicht ausgeführt, da es keine neuen Migrationen gibt, die übernommen 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>

Tipp

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 Datenbankverbindungszeichenfolge aus der Konfiguration Ihrer Anwendung. Es kann jedoch eine andere Datenbank migriert werden, wenn deren 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>

Hinweis

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. Während dieser Ansatz für die lokale Entwicklung und das Testen von Migrationen produktiv ist, ist er für die Verwaltung von Produktionsdatenbanken aus den folgenden Gründen ungeeignet:

  • Wenn mehrere Instanzen Ihrer Anwendung ausgeführt werden, könnten beide Anwendungen versuchen, die Migration gleichzeitig anzuwenden und dabei scheitern (oder schlimmer noch eine Datenbeschädigung verursachen).
  • Ä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.Migrate() auf, um Migrationen programmgesteuert anzuwenden. Eine typische ASP.NET-Anwendung kann z. B. die folgende Aktionen ausführen:

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

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

    host.Run();
}

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

Warnung

  • Überlegen Sie sorgfältig, bevor Sie diesen Ansatz in der Produktion anwenden. Die Erfahrung hat gezeigt, dass die Einfachheit dieser Bereitstellungsstrategie durch die Probleme, die sie mit sich bringt, zunichte gemacht wird. Erwägen Sie stattdessen das Generieren von SQL-Skripts aus Migrationen.
  • Rufen Sie EnsureCreated() nicht vor Migrate() auf. EnsureCreated() umgeht Migrationen zum Erstellen von Schemas, was dazu führt, dass Migrate() fehlerhaft ist.