2012-12-12 4 views
10

Ho uno scenario in cui vorrei cambiare il nome della chiave primaria in un'entità ed essere in grado di eseguire update-database -force. Vedi sotto per codice ed errore ricevendo quando provo.Come modificare il nome di una chiave primaria in codice EF Prima?

entità è stata:

public class Team 
{ 
    [Key] 
    [HiddenInput(DisplayValue = false)] 
    public virtual int Id { get; set; } 

    [Display(Name = "Full Name:")] 
    public virtual string Name { get; set; } 
} 

Entity cambiato in:

public class Team 
{ 
    [Key] 
    [HiddenInput(DisplayValue = false)] 
    public virtual int TeamId { get; set; } 

    [Display(Name = "Full Name:")] 
    public virtual string Name { get; set; } 
} 

quando corro Update-database -Force io ottenere il seguente errore.

Multiple identity columns specified for table 'Teams'. Only one identity column per table is allowed.

è una questione di convenzione di denominazione e ho bisogno di questo per essere teamid quando ho fanno riferimento questi ultimi, semplicemente conflitti Id con le classi di entità bambino.

Qualche idea su come posso farlo con successo?

+2

Si potrebbe mappare teamid al primario Id chiave con [colonna ("Id")] attributo o fare entrambe il nome della colonna e la variabile POCO devono essere nominato teamid? –

+0

@ marvc1 Sto provando il tuo suggerimento, ti informerò in un minuto – Komengem

+0

@ marvc1 hey amico, il tuo suggerimento sembra funzionare e vedo che hai dato una risposta qui sotto. – Komengem

risposta

4

Dipende dalla versione di EF che si sta utilizzando. Anche con le migrazioni il risultato che si vedrà è qualcosa del tipo:

"ID colonna di rilascio" e "aggiungi colonna TeamId".

Con questa operazione si perdono tutti i valori e le "connessioni bambino" ......

L'unica soluzione "sicura" sto vedendo a questo punto è un mix di Migrazioni e "operazioni a mano SQL".

soluzione facile:

1- tenendo in considerazione che si dispone già di una migrazione "base" creare la tabella con ID, ora creare la nuova migrazione con il "aggiornamento". Ora NON eseguirlo ancora.

2- Aprire il file e scrivere una nuova linea prima che le linee generate e utilizzare un comando SQL, qualcosa di simile:

 SQL("ALTER TABLE table_name RENAME COLUMN old_name to new_name;"); 

Questo cambierà il nome prima della migrazione elimina la colonna e creare un nuovo uno, quello che succederà è: cambi il nome prima dell'eliminazione, quindi l'eliminazione viene eseguita ma "fallirà" ma non danneggerà nulla.

Ma ora chiedi: perché lo faccio? beh se usi le migrazioni anche se elimini le righe per eliminare la colonna e ne crei una nuova, la prossima volta che creerai automaticamente un nuovo file di migrazione queste nuove linee saranno lì ... ecco perché.

RISPOSTE AGGIORNAMENTO # 1

Quando parlo di entità Migrazioni Framework mi riferisco a questo: http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx quando si esegue il '-Aggiungere migrazione AddBlogUrl' comando in Package Manager Console, un nuovo file (* .cs) è stato creato.

Esempio di questa file di migrazione file con comandi SQL:

public partial class AddAbsencesTypesAndCategories : DbMigration 
    { 
     public override void Up() 
     { 
      CreateTable(
       "pvw_AbsenceType", 
       c => new 
        { 
         Id = c.Int(nullable: false, identity: true), 
         Name = c.String(nullable: false), 
         CountAsVacation = c.Boolean(nullable: false), 
         IsIncremental = c.Boolean(nullable: false), 
        }) 
       .PrimaryKey(t => t.Id); 

      ..... 

      AddColumn("pvw_Absence", "CategoryId", c => c.Int(nullable: false)); 
         AddForeignKey("pvw_Absence", "StatusId", "pvw_AbsenceStatusType", "Id"); 
      AddForeignKey("pvw_Absence", "CategoryId", "pvw_AbsenceType", "Id"); 
      CreateIndex("pvw_Absence", "StatusId"); 
      CreateIndex("pvw_Absence", "CategoryId"); 
      DropColumn("pvw_Absence", "MainCategoryId"); 
      DropColumn("pvw_Absence", "SubCategoryId"); 
      ...... 
      Sql(@" 
             SET IDENTITY_INSERT [dbo].[pvw_AbsenceStatusType] ON 
        INSERT pvw_AbsenceStatusType (Id, Name) VALUES (1, N'Entwurf')      
             SET IDENTITY_INSERT [dbo].[pvw_AbsenceStatusType] OFF 
      ");  
      ..... 
     } 

     public override void Down() 
     { 
      ........ 
     } 
+0

Posso far funzionare questa idea, nella dichiarazione 2 quando dici aprire quel file, a quale file ti stai riferendo? In teoria, eseguivo quell'istruzione SQL in SQL Server Management Studio ma non sembra trovare il database desiderato. – Komengem

+0

Quando parlo di Entity Framework Migrations mi riferisco a questo: http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough. aspx Quando si esegue il comando "Add-Migration AddBlogUrl" in Package Manager Console, viene creato un nuovo file (* .cs). – Dryadwoods

+0

Non sono sicuro che EF5 crei questo file perché non riesco a trovarlo, a meno che non debba crearlo da solo. EF5 crea un Configuration.cs nella cartella Migration. Questo file ha una classe sealed interna che ha il suo pconstructor e un metodo seed. – Komengem

2

soluzione più semplice è quello di non rinominare la chiave primaria nel database e invece mappare la classe alla vostra chiave primaria e assegnando il nome che si desidera. In questo modo:

public class Team 
{ 
    [Key] 
    [HiddenInput(DisplayValue = false)] 
    [Column("Id")] //this attribute maps TeamId to the column Id in the database 
    public virtual int TeamId { get; set; } 

    [Display(Name = "Full Name:")] 
    public virtual string Name { get; set; } 
} 

Personalmente, manterrei il nome della classe come ID. La convenzione di denominazione [TableName + Id] è vecchia scuola e overkill per una chiave primaria (per una chiave esterna è buona). Per me aggiunge solo rumore alle tue linee di codice. team.TeamId non è migliore di team.Id.

+0

È una soluzione piacevole solo se non ti interessa i nomi nel Database. – Dryadwoods

+0

@emanyalpsid è quello che mi preoccupa ora, il codice è stato eseguito correttamente ma i nomi nel database rimangono come prima, non sono sicuro che mi piaccia questa idea. Ora sto valutando la possibilità di rilasciare il database e ricrearlo nuovamente, oltre a consentire la migrazione prima del codice abilitato, non dovrebbe richiedere molto tempo. – Komengem

+0

Se non si è preoccupati dei dati nel database, basta rilasciarlo e ricrearlo. –

2

Dopo aver giocato con il suggerimento sia di marvc1 che di emanyalpsid. Ho deciso di abbandonare il database e crearlo nuovamente. Ciò avviene semplicemente eliminando il database in Esplora server in VS2012 e assicurandosi che anche il file .mdf in App_Data venga eliminato. Di solito il file .mdf è nascosto, per vederlo appena sotto la barra degli strumenti di Esplora soluzioni clicca su Mostra tutti i file e lo vedrai. quando sono fatti questi passi, è sufficiente eseguire il codice qui sotto nella console di Package Manager:

update-database -Verbose 

-Verbose semplicemente permette di verificare ciò che si sta creando.

risposta del marvc1

funziona bene, tranne che non cambia i nomi nel database, se non sono troppo preoccupato per i nomi dei database, è il modo più sicuro per andare su di esso. Con nomi nel database voglio dire, In the entity Team, Id would still be Id and not TeamId