Stosowanie migracji

Po dodaniu migracji należy je wdrożyć i zastosować do baz danych. Istnieją różne strategie tego działania, a niektóre są bardziej odpowiednie dla środowisk produkcyjnych, a inne dla cyklu projektowania.

Note

Niezależnie od strategii wdrażania zawsze sprawdzaj wygenerowane migracje i przetestuj je przed zastosowaniem do produkcyjnej bazy danych. Migracja może spowodować usunięcie kolumny, gdy intencja miała ją zmienić lub może zakończyć się niepowodzeniem z różnych powodów, gdy zastosowano ją do bazy danych.

Wybieranie strategii wdrażania

W przypadku wdrażania automatycznego użyj pakietu migracji. Pakiet to artefakt wdrożenia, który można wygenerować w ciągłej integracji i wykonać później bez zestawu SDK .NET, narzędzi EF Core lub kodu źródłowego aplikacji. Zamiast tego należy użyć skryptu SQL , gdy przed zastosowaniem należy przejrzeć, zmodyfikować, zarchiwizować lub przekazać go administratorowi bazy danych.

W przypadku programowania dotnet ef database update lokalnego lub Update-Database jest zwykle najprostszą opcją. Projekty Aspirujące powinny używać integracji migracji programu Aspire EF Core do koordynowania lokalnego wykonywania migracji i publikowania pakietów lub skryptów.

Strategy Zalecane użycie Przed wykonaniem przejrzyj język SQL Wymaga zestawu SDK i źródła podczas wykonywania Używa blokowania migracji ef Uruchamia delegatów rozmieszczania ef
Skrypt SQL Wdrażanie sterowane przez administratora bazy danych lub z bramą przeglądową Yes No No No
Pakiet migracji Wdrożenie automatyczne No No Yes Yes
Narzędzia wiersza polecenia ef Lokalne programowanie i testowanie No Yes Yes Yes
Migracja środowiska uruchomieniowego Aplikacje, które akceptują kompromisy migracji startowej No No Yes Yes

Program EF Core 9 i nowsze używają blokady migracji. Operacje synchroniczne i wywoływanie narzędzi UseSeeding; operacje asynchroniczne wywołują metodę UseAsyncSeeding.

Użyj oddzielnej tożsamości do wdrożenia, która ma uprawnienia do zmiany schematu. Tożsamość używana przez aplikację w czasie wykonywania powinna zwykle mieć tylko uprawnienia, które aplikacja musi odczytywać i zapisywać dane.

Skrypty SQL

Skrypty SQL są zalecane, gdy proces wdrażania wymaga sprawdzenia lub zmiany wygenerowanego kodu SQL przed wykonaniem. Zalety tej strategii obejmują następujące elementy:

  • Skrypty SQL można przeglądać pod kątem dokładności; Jest to ważne, ponieważ stosowanie zmian schematu w produkcyjnych bazach danych jest potencjalnie niebezpieczną operacją, która może obejmować utratę danych.
  • W niektórych przypadkach skrypty można dostosować do określonych potrzeb produkcyjnej bazy danych.
  • Skrypty SQL mogą być używane w połączeniu z technologią wdrożeniową, a nawet mogą być generowane w ramach procesu Continuous Integration (CI).
  • Skrypty SQL mogą być udostępniane administratorowi bazy danych i mogą być zarządzane i archiwizowane oddzielnie.

Podstawowy sposób użycia

Następujące polecenie generuje skrypt SQL z pustej bazy danych do najnowszej migracji:

dotnet ef migrations script

Domyślnie polecenie zapisuje skrypt w standardowych danych wyjściowych. Użyj --output (lub -o) , aby utworzyć artefakt wdrożenia z przewidywalną nazwą:

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

Od do (zakres jest sugerowany)

Poniższy kod generuje skrypt SQL z danej migracji do najnowszej migracji.

dotnet ef migrations script AddNewTables

Od i Do

Polecenie poniżej generuje skrypt SQL z migracji określonej jako from do migracji określonej jako to.

dotnet ef migrations script AddNewTables AddAuditTable

Możesz użyć from, który jest nowszy niż to, aby wygenerować skrypt wycofywania.

Warning

Zanotuj potencjalne scenariusze utraty danych.

Generowanie skryptu akceptuje następujące dwa argumenty, aby wskazać, który zakres migracji należy wygenerować:

  • Ostatnia migracja „from” powinna być zastosowana do bazy danych przed uruchomieniem skryptu. Jeśli nie zastosowano żadnych migracji, określ wartość 0 jako domyślną.
  • Jest to ostatnia migracja, która zostanie zastosowana do bazy danych po uruchomieniu skryptu. Domyślnie jest to ostatnia migracja w projekcie.

Skrypty migracji aktualizują istniejącą bazę danych. Przed zastosowaniem skryptu należy aprowizować bazę danych za pośrednictwem procesu wdrażania infrastruktury lub administrowania bazą danych. Tworzenie bazy danych zwykle wymaga innego połączenia, podwyższonych uprawnień i konfiguracji specyficznej dla dostawcy.

Idempotentne skrypty SQL

Skrypty SQL wygenerowane powyżej można zastosować tylko w celu zmiany schematu z jednej migracji na inną; Użytkownik jest odpowiedzialny za odpowiednie zastosowanie skryptu i tylko do baz danych w prawidłowym stanie migracji. Program EF Core obsługuje również generowanie skryptów idempotentnych , które wewnętrznie sprawdzają, które migracje zostały już zastosowane (za pośrednictwem tabeli historii migracji) i stosują tylko brakujące. Jest to przydatne, jeśli nie wiesz dokładnie, jaka była ostatnia migracja zastosowana do bazy danych, lub jeśli wdrażasz w wielu bazach danych, które mogą znajdować się w innej migracji.

Obsługa skryptów idempotentnych zależy od dostawcy bazy danych. Na przykład sqlite nie obsługuje obecnie generowania skryptów migracji idempotentnych.

Następujące elementy generują migracje idempotentne:

dotnet ef migrations script --idempotent

Narzędzia wiersza polecenia

Narzędzia wiersza polecenia ef mogą służyć do stosowania migracji do bazy danych. Chociaż produktywne w przypadku lokalnego tworzenia i testowania migracji, takie podejście nie jest idealne do zarządzania produkcyjnymi bazami danych:

  • Polecenia SQL są stosowane bezpośrednio przez narzędzie bez możliwości sprawdzenia lub zmodyfikowania ich przez dewelopera. Może to być niebezpieczne w środowisku produkcyjnym.
  • Zestaw SDK .NET i narzędzie EF muszą być zainstalowane na serwerach produkcyjnych i wymagają kodu źródłowego projektu.

Następujące aktualizacje bazy danych do najnowszej migracji:

dotnet ef database update

Poniżej zaktualizujesz bazę danych do określonej migracji:

dotnet ef database update AddNewTables

Należy pamiętać, że można tego również użyć do przywrócenia wcześniejszej migracji.

Warning

Zanotuj potencjalne scenariusze utraty danych.

Aby uzyskać więcej informacji na temat stosowania migracji za pomocą narzędzi wiersza polecenia, zobacz dokumentację narzędzi platformy EF Core.

Środowisko i konfiguracja

Narzędzia wykonują kod aplikacji, aby skonstruować element DbContext. Wybór dostawcy, parametry połączenia i konfiguracja modelu mogą w związku z tym zależeć od środowiska aplikacji. Narzędzia czasu projektowania platformy EF Core używają Development środowiska, gdy ani nie ASPNETCORE_ENVIRONMENTDOTNET_ENVIRONMENT jest ustawione.

Ustaw środowisko jawnie podczas generowania artefaktu wdrożenia i podczas wykonywania pakietu. Na przykład w programie PowerShell:

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

Lub w powłoce zgodnej z modelem POSIX:

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

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

Uniemożliwia to również nieoczekiwane ładowanie wpisów tajnych użytkownika dewelopera pakietu. Bezpieczniejsze domyślne środowisko pakietów jest śledzone przez dotnet/efcore#36188. Wybór środowiska w środowisku publikowania Visual Studio jest śledzony przez narzędzie dotnet/efcore#11950.

Nie przechowuj parametrów połączenia produkcyjnego w kontroli źródła ani nie osadzaj ich w pakiecie. Podaj połączenie wdrożenia z magazynu wpisów tajnych systemu wdrażania. Tożsamość wdrożenia powinna mieć uprawnienia do schematu; normalna tożsamość aplikacji zwykle nie powinna.

Bundles

Pakiety migracji to samodzielne pliki wykonywalne, które można użyć do zastosowania migracji w bazie danych. Dotyczą one niektórych niedociągnięć skryptu SQL i narzędzi wiersza polecenia:

  • Wykonywanie skryptów SQL wymaga dodatkowych narzędzi.
  • Obsługa transakcji i zachowanie związane z kontynuowaniem działania w przypadku błędu w tych narzędziach są niespójne i czasami nieoczekiwane. Może to pozostawić bazę danych w stanie niezdefiniowanym, jeśli wystąpi błąd podczas stosowania migracji.
  • Pakiety można wygenerować w ramach procesu ciągłej integracji (CI) i łatwo wykonać później w ramach procesu wdrażania.
  • Pakiety można wykonywać bez instalowania zestawu SDK .NET lub narzędzia EF (a nawet środowiska uruchomieniowego .NET, gdy jest on samodzielny) i nie wymagają kodu źródłowego projektu.
  • Pakiety używają blokady migracji i uruchamiania skonfigurowanej UseSeeding logiki programu EF Core.

W przeciwieństwie do skryptu SQL pakiet nie zapewnia obecnie możliwości inspekcji bazy danych SQL, która zostanie wykonana lub wyświetli listę zawartych w nim migracji. Jeśli wdrożenie wymaga przeglądu sql, zamiast tego wygeneruj skrypt. Ulepszenia inspekcji pakietów są śledzone przez narzędzie dotnet/efcore#25872.

Następujące elementy generują pakiet:

dotnet ef migrations bundle --output artifacts/efbundle

Następujące elementy generują samodzielny pakiet dla systemu Linux:

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

Aby uzyskać więcej informacji na temat tworzenia pakietów, zobacz dokumentację narzędzi EF Core.

efbundle

Wynikowy plik wykonywalny jest domyślnie nazwany efbundle . Może służyć do aktualizowania bazy danych do najnowszej migracji. Jest to odpowiednik uruchamiania dotnet ef database update lub Update-Database.

Arguments:

Argument Description
<MIGRATION> Migracja docelowa. Jeśli wartość "0", wszystkie migracje zostaną przywrócone. Domyślnie jest to ostatnia migracja.

Options:

Option Short Description
--connection <CONNECTION> Ciąg połączenia do bazy danych. Domyślnie używana jest wartość określona w elemencie AddDbContext lub OnConfiguring.
--verbose -v Pokaż szczegółowe dane wyjściowe.
--no-color Nie koloruj danych wyjściowych.
--prefix-output Prefiks danych wyjściowych z poziomem.

Poniższy przykład dotyczy migracji do lokalnego wystąpienia SQL Server przy użyciu określonej nazwy użytkownika i poświadczeń:

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

Aby wycofać bazę danych, przekaż migrację, która powinna pozostać zastosowana. Przekazywanie 0 przywraca wszystkie migracje:

.\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

Wycofanie wykonuje operacje Down każdej migracji nowszej niż docelowa i może spowodować utratę danych. Przejrzyj i przetestuj zachowanie wycofywania przed użyciem go na danych produkcyjnych.

Skonfigurowany kod rozmieszczania jest uruchamiany po obniżeniu poziomu. Musi tolerować schemat migracji docelowej, w tym brakujący schemat aplikacji, gdy elementem docelowym jest 0.

Warning

Jeśli konfiguracja kontekstu odczytuje appsettings.jsonwartość , skopiuj wymagane pliki ustawień wraz z pakietem. Pliki konfiguracji są rozpoznawane z katalogu wykonawczego pakietu. Nie umieszczaj w tych plikach wpisów tajnych produkcyjnych; podaj je za pośrednictwem bezpiecznego źródła konfiguracji lub --connection opcji.

Kontenery i zadania wdrażania

Wygeneruj pakiet podczas kompilacji i uruchom go jako zadanie wdrożenia jednorazowego, gdy baza danych jest w dobrej kondycji. Nie instaluj zestawu SDK ani nie uruchamiaj dotnet ef go w obrazie aplikacji i nie uruchamiaj migracji każdej repliki aplikacji z punktu wejścia. Skonfiguruj platformę wdrażania, aby nie ponownie uruchomić kontenera migracji po pomyślnym zakończeniu.

W przypadku aplikacji AddEFMigrations Aspire można koordynować migracje podczas opracowywania lokalnego. Podczas publikowania PublishAsMigrationBundle program może emitować pakiet lub obraz kontenera i PublishAsMigrationScript emitować skrypt SQL. Zobacz Apply EF Core migrations in Aspire for one-shot job configuration for Azure Container Apps, Docker Compose, and Kubernetes (Stosowanie migracji platformy EF Core w programie Aspire), aby uzyskać informacje na temat konfiguracji zadań jednorazowych dla Azure Container Apps, narzędzia Docker Compose i platformy Kubernetes.

Przykład pakietu migracji przedstawia dwie migracje SQLite, rozmieszczanie idempotentne, przekazywanie aplikacji i wycofywanie bezpieczne rozmieszczanie.

Przykład pakietu migracji

Pakiet wymaga uwzględnienia migracji. Są one tworzone przy użyciu dotnet ef migrations add zgodnie z opisem w Tworzenie pierwszej migracji. Po przygotowaniu migracji do wdrożenia, utwórz pakiet przy użyciu dotnet ef migrations bundle. Przykład:

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>

Dane wyjściowe są plikiem wykonywalnym odpowiednim dla docelowego systemu operacyjnego. W moim przypadku jest to Windows x64, więc otrzymuję efbundle.exe umieszczony w moim folderze lokalnym. Uruchomienie tego pliku wykonywalnego powoduje zastosowanie zawartych w nim migracji:

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

Podobnie jak w przypadku dotnet ef database update lub Update-Database, migracje są stosowane do bazy danych tylko wtedy, gdy nie zostały jeszcze zastosowane. Na przykład uruchomienie tego samego pakietu nie powoduje niczego, ponieważ nie ma nowych migracji do zastosowania:

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

Jeśli jednak zmiany w modelu zostaną wprowadzone i zostaną wygenerowane kolejne migracje za pomocą dotnet ef migrations addpolecenia , można je połączyć w nowy plik wykonywalny gotowy do zastosowania. Przykład:

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

Za --force pomocą opcji można zastąpić istniejący pakiet nowym.

Wykonanie tego nowego pakietu zastosowuje te dwie nowe migracje do bazy danych.

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

Domyślnie pakiet używa ciągu połączenia bazy danych z konfiguracji aplikacji. Można jednak zmigrować inną bazę danych, przekazując ciąg połączenia w wierszu poleceń. Przykład:

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

Tym razem wszystkie trzy migracje zostały zastosowane, ponieważ żadna z nich nie została jeszcze zastosowana do produkcyjnej bazy danych.


Stosowanie migracji w czasie wykonywania

Aplikacja może stosować migracje programowo, zazwyczaj podczas uruchamiania. Program EF Core 9 lub nowszy chroni wykonywanie migracji za pomocą blokady całej bazy danych, dzięki czemu może to być akceptowalne dla aplikacji, które preferują proste wdrożenie i mogą tolerować zachowanie migracji uruchamiania. Oddzielny krok wdrażania migracji jest nadal preferowany, gdy ważne jest przejrzenie poświadczeń o najniższych uprawnieniach, skoordynowane wdrożenie lub wysoka dostępność.

Rozważ następujące kompromisy:

  • W przypadku wersji programu EF wcześniejszych niż 9, jeśli uruchomiono wiele wystąpień aplikacji, obie aplikacje mogą próbować stosować migrację współbieżnie i zakończyć się niepowodzeniem (lub co gorsza, spowodować uszkodzenie danych).
  • Podobnie jeśli aplikacja uzyskuje dostęp do bazy danych podczas migrowania innej aplikacji, może to spowodować poważne problemy.
  • Aby zmodyfikować schemat bazy danych, aplikacja musi mieć podwyższony poziom dostępu. Zazwyczaj dobrym rozwiązaniem jest ograniczenie uprawnień bazy danych aplikacji w środowisku produkcyjnym.
  • W przypadku problemu ważne jest, aby móc wycofać zastosowaną migrację. Inne strategie zapewniają to łatwo i bez dodatkowej konfiguracji.
  • Polecenia SQL są stosowane bezpośrednio przez program bez możliwości sprawdzenia lub zmodyfikowania ich przez dewelopera. Może to być niebezpieczne w środowisku produkcyjnym.

Aby programowo zastosować migracje, wywołaj metodę context.Database.MigrateAsync(). Na przykład typowa aplikacja ASP.NET może wykonać następujące czynności:

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();
}

Należy pamiętać, że MigrateAsync() opiera się na IMigrator usłudze, która może być używana w bardziej zaawansowanych scenariuszach. Użyj polecenia myDbContext.GetInfrastructure().GetService<IMigrator>() , aby uzyskać do niego dostęp.

Warning

  • Przed zastosowaniem tego podejścia w środowisku produkcyjnym należy dokładnie rozważyć. Preferuj pakiet migracji na potrzeby automatyzacji lub skryptu SQL podczas przeglądania i zatwierdzania.
  • Nie dzwonij EnsureCreatedAsync() przed MigrateAsync(). EnsureCreatedAsync() Pomija migracje w celu utworzenia schematu, co powoduje MigrateAsync() niepowodzenie.

Blokowanie migracji

Począwszy od wersji EF Core 9, MigrateAsync oraz Migrate automatycznie uzyskują blokadę dla całej bazy danych przed zastosowaniem wszelkich migracji. Chroni to przed uszkodzeniem bazy danych, które może wynikać z wielu wystąpień aplikacji, które jednocześnie uruchamiają migracje, co jest typowym scenariuszem podczas stosowania migracji w czasie wykonywania. Blokada jest przechowywana przez czas trwania wykonywania migracji, w tym dowolny kod inicjujący i jest automatycznie zwalniana po zakończeniu operacji.

Blokowanie migracji ma zastosowanie, gdy migracje są stosowane przy użyciu dowolnej z następujących metod:

  • dotnet ef database update (interfejs wiersza polecenia .NET)
  • Update-Database (Konsola Menedżera pakietów)
  • Pakiety migracji
  • MigrateAsync and Migrate (migracja środowiska uruchomieniowego)

Skrypty SQL nie mają wpływu na blokowanie migracji, ponieważ są one stosowane poza programem EF Core.

Note

Począwszy od EF Core 9 wywołanie Migrate() lub MigrateAsync() spowoduje zgłoszenie wyjątku, gdy model zawiera oczekujące zmiany względem ostatniej migracji (identyfikator zdarzenia ostrzeżenia RelationalEventId.PendingModelChangesWarning). Aby wykryć ten warunek przed wdrożeniem, użyj polecenia dotnet ef migrations has-pending-model-changes w potoku CI/CD. Ostrzeżenie można pominąć za pośrednictwem ConfigureWarnings (ignorowanie RelationalEventId.PendingModelChangesWarning) w razie potrzeby, ale zwykle nie jest to zalecane w scenariuszach produkcyjnych. Zobacz informację o zmianie powodującej niezgodność, aby uzyskać więcej informacji.

Warning

Mechanizm blokowania różni się znacznie w zależności od dostawców baz danych i może obejmować problemy specyficzne dla dostawcy. Na przykład dostawca SQLite używa tabeli blokady, która może zostać porzucona, jeśli proces zostanie nieoczekiwanie zakończony. Aby uzyskać szczegółowe informacje, zawsze zapoznaj się z dokumentacją dostawcy.

Ograniczenia