2013-02-12 10 views
29

Sono nuovo al codice EF5 Prima di tutto e sto armeggiando con una dimostrazione di concetto prima di imbarcarmi in un progetto al lavoro.Primo codice EF5: modifica di un tipo di colonna con le migrazioni

mi hanno inizialmente creato un modello che sembrava qualcosa di simile

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

E ho aggiunto alcuni record utilizzando una piccola applicazione MVC ho attaccato sulla parte superiore.

Ora voglio cambiare la colonna posizione per un enum, qualcosa di simile:

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 
} 

Quando aggiungo la nuova migrazione ottengo:

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

ma quando ho eseguito update-base di dati che ottiene un errore

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

C'è un modo nella migrazione per troncare la tabella prima che venga eseguita l'istruzione altera ?

So che posso aprire il database e farlo manualmente, ma c'è un modo più intelligente?

+2

Io suggerirei per gli sviluppatori in posizioni simili che vedono se la conversione viene gestita automaticamente da Entity Framework prima di seguire alcune delle risposte in questa pagina. Ad esempio, ho trovato che gestisce la conversione tra una stringa e un decimale e torna indietro senza alcun aiuto da parte mia: la migrazione generata da Add-Migration funziona correttamente. Ovviamente, provalo su un database locale/di test prima di applicarlo alla produzione! – pipedreambomb

risposta

45

Il modo più intelligente è probabilmente quello di non alterare i tipi. Se avete bisogno di fare questo, io suggerirei di fare le seguenti operazioni:

  1. aggiungere una nuova colonna con il nuovo tipo di
  2. Usa Sql() di prendere in consegna i dati dalla colonna originale utilizzando un'istruzione di aggiornamento
  3. Rimuovere la vecchia colonna
  4. Rinominare la nuova colonna

tutto questo può essere fatto nello stesso migrazione, verrà creato lo script SQL corretta. Puoi saltare il passaggio 2 se vuoi che i tuoi dati vengano scartati. Se si desidera riprenderlo, aggiungere l'istruzione appropriata (può contenere anche un'istruzione switch).

Sfortunatamente Code First Migrations non fornisce modi più semplici per ottenere ciò.

Ecco il codice di esempio:

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

Una nota veloce: usare una colonna temporanea è l'unico modo che ho trovato per fare ciò durante la migrazione di 'Giù()'.Gli aggiornamenti dello schema sembrano essere in esecuzione all'interno di una transazione che contiene anche il comando 'Sql()', poiché un aggiornamento di colonna dai valori di 'Integer' a' String' fallisce con lo stesso messaggio di errore-questa volta su 'Sql() 'invece di' AlterColumn() '. Anche se eseguiamo 'Sql()' DOPO 'AlterColumn()'. – InteXX

12

Sulla base di @ JustAnotherUserYouMayKnow risposta, ma più facile.

Prova innanzitutto eseguire Sql() di comando e quindi 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

Mi piace più della risposta contrassegnata: non ha bisogno di una colonna temporanea. – Marcel

Problemi correlati