29

Jestem nowym użytkownikiem kodu EF5 Najpierw i majstruję z proof-of-concept przed rozpoczęciem projektu w pracy.Kod EF5 Najpierw - zmiana typu kolumnowego z migracjami

ja początkowo stworzył model, który wyglądał mniej więcej tak

public class Person { 
    public int Id { get; set; } 
    public string FirstName { get; set;} 
    public string Surname {get;set;} 
    public string Location {get;set;} 
} 

I dodałem kilka rekordów przy użyciu trochę aplikacji MVC Wsadziłem na górze.

Teraz chcę zmienić kolumnę lokalizacji do wyliczenia, coś jak:

public class Person { 
    public int Id { get; set; } 
    public string FirstName { get; set;} 
    public string Surname {get;set;} 
    public Locations Location {get;set;} 
} 

public enum Locations { 
    London = 1, 
    Edinburgh = 2, 
    Cardiff = 3 
} 

Kiedy dodać nową migrację uzyskać:

AlterColumn("dbo.People", "Location", c => c.Int(nullable: false)); 

ale kiedy uruchomić update-bazy danych I uzyskać błąd

Conversion failed when converting the nvarchar value 'London' to data type int. 

Czy istnieje sposób migracji do obcinania tabeli przed uruchomieniem instrukcji alter ?

Wiem, że mogę otworzyć bazę danych i ręcznie to zrobić, ale czy istnieje mądrzejszy sposób?

+2

Sugeruję dla programistów w podobnej sytuacji, że oni sprawdzić, czy konwersja jest wykonywana automatycznie przez Entity Framework przed wykonaniem niektórych odpowiedziach na tej stronie. Na przykład, znalazłem, że obsługuje konwersję między ciągiem znaków i dziesiętne iz powrotem bez mojej pomocy - migracji, że generowane przez Add-Migration działa dobrze. Oczywiście, spróbuj go w lokalnej/testowej bazie danych przed zastosowaniem do produkcji! – pipedreambomb

Odpowiedz

45

Najmądrzejszy sposób to prawdopodobnie nie zmieniać typów. Jeśli musisz to zrobić, sugeruję, aby wykonać następujące czynności:

  1. Dodaj nową kolumnę z nowego typu
  2. Korzystanie Sql() przejąć dane z oryginalnej kolumny stosując instrukcję aktualizacji
  3. Wyjmij starą kolumnę
  4. Zmień nazwę nowej kolumny

To wszystko może być wykonane w tej samej migracji, zostanie utworzony poprawny skrypt SQL. Możesz pominąć krok 2, jeśli chcesz, aby dane zostały odrzucone. Jeśli chcesz go przejąć, dodaj odpowiednią instrukcję (może również zawierać instrukcję switch).

Niestety Migracje po Code First nie zapewniają łatwiejszych sposobów osiągnięcia tego.

Oto przykładowy kod:

AddColumn("dbo.People", "LocationTmp", c => c.Int(nullable: false)); 
Sql(@" 
    UPDATE dbp.People 
    SET LocationTmp = 
     CASE Location 
      WHEN 'London' THEN 1 
      WHEN 'Edinburgh' THEN 2 
      WHEN 'Cardiff' THEN 3 
      ELSE 0 
     END 
    "); 
DropColumn("dbo.People", "Location"); 
RenameColumn("dbo.People", "LocationTmp", "Location"); 
+0

Krótka uwaga: użycie tymczasowej kolumny jest jedynym sposobem, w jaki znalazłem to podczas migracji 'W dół()'.Wydaje się, że aktualizacje schematu działają wewnątrz transakcji, która zawiera także polecenie 'Sql()', ponieważ aktualizacja kolumny z wartości 'Integer' z powrotem do' String' kończy się niepowodzeniem z tym samym komunikatem o błędzie - tym razem na 'Sql() 'zamiast' AlterColumn() '. To, mimo że uruchamiamy 'Sql()' AFTER 'AlterColumn()'. – InteXX

12

oparciu o użytkownika @ JustAnotherUserYouMayKnow odpowiedź, ale łatwiejsze.

Spróbuj najpierw wykonać Sql() polecenie, a następnie AlterColumn():

Sql(@" 
    UPDATE dbo.People 
    SET Location = 
     CASE Location 
      WHEN 'London' THEN 1 
      WHEN 'Edinburgh' THEN 2 
      WHEN 'Cardiff' THEN 3 
      ELSE 0 
     END 
    "); 
AlterColumn("dbo.People", "Location", c => c.Int(nullable: false)); 
+1

Podoba mi się więcej niż zaznaczona odpowiedź: nie potrzebuje tymczasowej kolumny. – Marcel

Powiązane problemy