Entity Framework wycofywanie i usuwanie złej migracji

174

Używam EF 6,0 do mojego projektu w C # z ręcznymi migracjami i aktualizacjami. Mam w bazie około 5 migracji, ale zdałem sobie sprawę, że ostatnia migracja była zła i nie chcę jej. Wiem, że mogę wrócić do poprzedniej migracji, ale kiedy dodam nową (naprawioną) migrację i uruchomię Update-Database, stosowana jest nawet błędna migracja.

Próbowałem wrócić do poprzedniej migracji i usunąć plik z błędną migracją. Ale potem, kiedy próbuję dodać nową migrację, pojawia się błąd podczas aktualizacji bazy danych, ponieważ plik migracji jest uszkodzony (dokładniej, pierwsza linia kodu zmienia nazwę tabeli A na B i jest następna, EF próbuje zaktualizować tabelę za pomocą nazwa A - może to jakiś błąd EF).

Czy jest jakieś zapytanie, które mogę uruchomić, które powie EF coś w stylu „Zapomnij o ostatniej migracji, jakby nigdy nie istniała, była zła”? Coś w rodzaju Remove-Migration.

Edit1 Znalazłem rozwiązanie odpowiednie dla mnie. Zmiana modelu na dobry stan i uruchomienie Add-Migration TheBadMigration -Force. Spowoduje to ponowne utworzenie szkieletu ostatniej, niezastosowanej migracji.

W każdym razie to wciąż nie daje pełnej odpowiedzi na pierwotne pytanie. Jeśli zaktualizuję bazę danych do złej migracji, nie znalazłem dobrego sposobu na przywrócenie i utworzenie nowej migracji, z wyjątkiem złej.

Dzięki

Martin Brabec
źródło
Musiałem zrestartować Visual Studio i wtedy zaczęło działać poprawnie. Zdarzyło mi się to już kilka razy, zawsze po zamieszaniu z migracjami bez faktycznej aktualizacji bazy danych, więc dzieje się coś dziwnego z narzędziami.
Andrei Dvoynos

Odpowiedzi:

167

Masz 2 opcje:

  • Możesz zdjąć Down ze złej migracji i umieścić ją w nowej migracji (będziesz musiał również wprowadzić kolejne zmiany w modelu). To skutecznie przechodzi do lepszej wersji.

    Używam tej opcji w przypadku rzeczy, które trafiły do ​​wielu środowisk.

  • Inną opcją jest faktyczne uruchomienie Update-Database –TargetMigration: TheLastGoodMigrationwe wdrożonej bazie danych, a następnie usunięcie migracji z rozwiązania. Jest to coś w rodzaju alternatywy dla hulk smash i wymaga wykonania tej operacji na dowolnej bazie danych wdrożonej w złej wersji.

    Uwaga: aby ponownie przenieść migrację do sieci, możesz użyć Add-Migration [existingname] -Force. Spowoduje to jednak zastąpienie istniejącej migracji, więc pamiętaj, aby zrobić to tylko wtedy, gdy usunąłeś istniejącą migrację z bazy danych. Działa to tak samo, jak usunięcie istniejącego pliku migracji i uruchomienieadd-migration

    Korzystam z tej opcji podczas programowania.

Nie kochany
źródło
1
Opcja Hulk Smash nie działa. Nie zastosowałem jeszcze złej migracji do bazy danych. Próbowałem, ale nie działało, ponieważ nazwy tabel podałem w oryginalnym pytaniu. Pierwsza opcja mi się nie podoba, bo wygląda na to, że musiałbym zmienić kod migracji. Jeśli zrobię to słabo, mogę to wszystko zepsuć.
Martin Brabec
8
Jeśli jeszcze nie zastosowałeś złej migracji, nic nie stoi na przeszkodzie, abyś ją usunął i ponownie utworzył szkielet lub poprawił uszkodzoną migrację.
Nie uwielbiałem
4
Odpowiedzią jest „hulk smash”, działa na mnie podczas programowania i chcę dodać coś do migracji, którą przegapiłem. Myślę, że powody, dla których to nie zadziałało dla Martina, są niezwiązane (lub prawdopodobnie związane ze zmianą schematu bazy danych ręcznie)
rethenhouser2
1
@BenRethmeier z zasady używam opcji hulk smash tylko podczas programowania. W prod zawsze tworzę nową migrację, aby rozwiązać problem. Powodem jest to, że potrzebujesz ręcznej interwencji, jeśli obniżasz wersję bazy danych. Nie lubię niczego, co wymaga ręcznej interwencji w prod.
Nie uwielbiałem
1
HULK SMASH! druga migracja w ten sam sposób - żadnych błędów - powrót do normy
Traci
127

Jak wskazuje pytanie, dotyczy to migracji w środowisku typu programistycznego, które nie zostało jeszcze wydane.

Ten problem można rozwiązać w następujących krokach: przywróć bazę danych do ostatniej dobrej migracji, usuń błędną migrację z projektu Entity Framework, wygeneruj nową migrację i zastosuj ją do bazy danych. Uwaga: Na podstawie komentarzy te dokładne polecenia mogą już nie mieć zastosowania, jeśli używasz EF Core.

Krok 1: Przywróć poprzednią migrację

Jeśli jeszcze nie zastosowałeś migracji, możesz pominąć tę część. Aby przywrócić schemat bazy danych do poprzedniego punktu, użyj polecenia Update-Database z opcją -TargetMigration, określ ostatnią dobrą migrację. Jeśli kod struktury jednostki znajduje się w innym projekcie w rozwiązaniu, może być konieczne użycie opcji „-Project” lub przełączenie domyślnego projektu w konsoli menedżera pakietów.

Update-Database TargetMigration: <name of last good migration>

Aby uzyskać nazwę ostatniej dobrej migracji, użyj polecenia „Get-Migrations”, aby pobrać listę nazw migracji, które zostały zastosowane w Twojej bazie danych.

PM> Get-Migrations
Retrieving migrations that have been applied to the target database.
201508242303096_Bad_Migration
201508211842590_The_Migration_applied_before_it
201508211440252_And_another

Ta lista pokazuje najpierw najnowsze zastosowane migracje. Wybierz migrację, która ma miejsce na liście po migracji, do której chcesz przejść na starszą wersję, tj. Migrację zastosowaną przed migracją, na którą chcesz obniżyć. Teraz wydaj aktualizację bazy danych.

Update-Database TargetMigration: "<the migration applied before it>"

Wszystkie migracje zastosowane po migracji zostaną obniżone w kolejności, zaczynając od najnowszej migracji zastosowanej jako pierwsza.

Krok 2: Usuń migrację z projektu

remove-migration name_of_bad_migration

Jeśli remove-migrationpolecenie nie jest dostępne w Twojej wersji Entity Framework, usuń ręcznie pliki niechcianej migracji folderu „Migracje” projektu EF. W tym momencie możesz utworzyć nową migrację i zastosować ją do bazy danych.

Krok 3: Dodaj nową migrację

add-migration my_new_migration

Krok 4: Zastosuj migrację do bazy danych

update-database
David Sopko
źródło
6
Wydaje się, że w przypadku EF Core Get-Migrations został usunięty.
Kevin Burton
1
Krok 2 ! - Bardzo przydatna funkcja. Jak wspomniał @KevinBurton. A następnie add-migration "new migration",update-database
Alexander Frolov
2
Update-Database –migration: „<migracja zastosowana przed nią>” @David Sopko
Fuat
Dzięki @AlexanderFrolov Zaktualizowałem rozwiązanie, aby odzwierciedlić Twoje komentarze.
David Sopko
1
musimy użyć usuwania migracji po kroku 2
Rahul
55

Dla osób używających EF Core z ASP.NET Core v1.0.0 miałem podobny problem i użyłem następujących poleceń, aby go poprawić (post @ DavidSopko wskazał mi właściwy kierunek, ale szczegóły są nieco inne dla EF Core) :

Update-Database <Name of last good migration>
Remove-Migration

Na przykład w moim obecnym rozwoju polecenie stało się

PM> Update-Database CreateInitialDatabase
Done.
PM> Remove-Migration
Done.
PM> 

Funkcja Remove-Migration usunie ostatnią zastosowaną migrację. Jeśli masz bardziej złożony scenariusz z wieloma migracjami do usunięcia (miałem tylko 2, początkową i złą), sugeruję przetestowanie kroków w fikcyjnym projekcie.

Obecnie nie wydaje się, aby było polecenie Get-Migrations w EF Core (v1.0.0), więc musisz zajrzeć do folderu migracji i zapoznać się z wykonanymi czynnościami. Jest jednak fajne polecenie pomocy:

PM> get-help entityframework

Odświeżanie bazy danych w VS2015 SQL Server Object Explorer, wszystkie moje dane zostały zachowane, a migracja, którą chciałem przywrócić, zniknęła :)

Początkowo próbowałem samodzielnie usunąć migrację i stwierdziłem, że polecenie błędu jest mylące:

System.InvalidOperationException: migracja „...” została już zastosowana do bazy danych. Odrzuć to i spróbuj ponownie. Jeśli migracja została zastosowana do innych baz danych, rozważ przywrócenie jej zmian przy użyciu nowej migracji.

Są już sugestie dotyczące ulepszenia tego sformułowania, ale chciałbym, aby błąd mówił coś takiego:

Uruchom Update-Database (ostatnia dobra nazwa migracji), aby przywrócić schemat bazy danych do tego stanu. To polecenie spowoduje cofnięcie wszystkich migracji, które miały miejsce po migracji określonej w Update-Database. Następnie możesz uruchomić Remove-Migration (nazwa migracji do usunięcia)

Dane wyjściowe z polecenia pomocy EF Core są następujące:

 PM> get-help entityframework
                     _/\__
               ---==/    \\
         ___  ___   |.    \|\
        | __|| __|  |  )   \\\
        | _| | _|   \_/ |  //|\\
        |___||_|       /   \\\/\\

TOPIC
    about_EntityFrameworkCore

SHORT DESCRIPTION
    Provides information about Entity Framework Core commands.

LONG DESCRIPTION
    This topic describes the Entity Framework Core commands. See https://docs.efproject.net for information on Entity Framework Core.

    The following Entity Framework cmdlets are included.

        Cmdlet                      Description
        --------------------------  ---------------------------------------------------
        Add-Migration               Adds a new migration.

        Remove-Migration            Removes the last migration.

        Scaffold-DbContext          Scaffolds a DbContext and entity type classes for a specified database.

        Script-Migration            Generates a SQL script from migrations.

        Update-Database             Updates the database to a specified migration.

        Use-DbContext               Sets the default DbContext to use.

SEE ALSO
    Add-Migration
    Remove-Migration
    Scaffold-DbContext
    Script-Migration
    Update-Database
    Use-DbContext
Richard Logwood
źródło
6

Możesz także użyć

Remove-Migration -Force

Spowoduje to przywrócenie i usunięcie ostatniej zastosowanej migracji

Daniël Tulp
źródło
4

Najpierw zaktualizuj swoją ostatnią idealną migrację za pomocą tego polecenia:

Update-Database TargetMigration

Przykład:

Update-Database -20180906131107_xxxx_xxxx

Następnie ręcznie usuń nieużywaną migrację.

Abdus Salam Azad
źródło
2
powinno to być: Update-Database -TargetMigration 20180906131107_xxxx_xxxx
Elger Mensonides,
Update-Database 20180906131107_xxxx_xxxx(bez myślnika) działało dla mnie. Żadna wersja TargetMigrationjako przełącznik nie działała. Te polecenia wydają się być ruchomym celem (tj. Zmienić je w każdej wersji)?
Sum None
3

TargetMigrationWydaje się , że od .NET Core 2.2 zniknął:

get-help Update-Database

NAME
    Update-Database

SYNOPSIS
    Updates the database to a specified migration.


SYNTAX
    Update-Database [[-Migration] <String>] [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>]


DESCRIPTION
    Updates the database to a specified migration.


RELATED LINKS
    Script-Migration
    about_EntityFrameworkCore 

REMARKS
    To see the examples, type: "get-help Update-Database -examples".
    For more information, type: "get-help Update-Database -detailed".
    For technical information, type: "get-help Update-Database -full".
    For online help, type: "get-help Update-Database -online"

Więc to działa teraz dla mnie:

Update-Database -Migration 20180906131107_xxxx_xxxx

Jak również (bez -Migrationprzełącznika):

Update-Database 20180906131107_xxxx_xxxx

Ponadto nie można już czysto usuwać folderów migracji bez zsynchronizowania Migawki modelu. Więc jeśli nauczysz się tego na własnej skórze i skończysz z pustą migracją, w której wiesz, że powinny nastąpić zmiany, możesz uruchomić (żadne przełączniki nie są potrzebne do ostatniej migracji):

Remove-migration

Spowoduje to wyczyszczenie bałaganu i przeniesie Cię tam, gdzie trzeba, mimo że ostatni folder migracji został usunięty ręcznie.

Suma Brak
źródło
0

W przypadku EF 6 tutaj jest jedna linijka, jeśli dużo przebudowujesz rusztowania w trakcie opracowywania. Po prostu zaktualizuj zmienne, a następnie użyj strzałki w górę w konsoli menedżera pakietów, aby przepłukać i powtórzyć.

$lastGoodTarget = "OldTargetName"; $newTarget = "NewTargetName"; Update-Database -TargetMigration "$lastGoodTarget" -Verbose; Add-Migration "$newTarget" -Verbose -Force

Dlaczego jest to konieczne? Nie jestem pewien, które wersje EF6 to ma zastosowanie, ale jeśli nowy cel migracji został już zastosowany, użycie `` -Force '' do ponownego szkieletowania w Add-Migration nie spowoduje ponownego szkieletu, ale zamiast tego utworzy nowy plik (to jest dobre rzecz, ponieważ nie chciałbyś stracić swojego „upadku”). Powyższy fragment kodu wykonuje najpierw 'Down', jeśli to konieczne, a następnie -Force działa poprawnie, aby ponownie ustawić rusztowanie.

pani
źródło