2015-11-17 11 views
5

Utilizzando il primo modello di codice Entity Framework 6.1, qual è il modo migliore per modificare l'indice cluster su una tabella rispetto all'impostazione predefinita ID a un altro set di colonne. Azure non consente una tabella senza un indice cluster.Come modificare un indice cluster nel modello Entity Framework 6.1 Code First e applicarlo a un database Azure

public partial class UserProfile 
    { 
    public override Guid ID { get; set; } 

    [Index("CI_UserProfiles_UserID", IsClustered = true)] 
    public Guid UserID { get; set; } 

    [Required] 
    public Guid FieldID { get; set; } 

    [Required] 
    [StringLength(400)] 
    public string Value { get; set; } 
} 

Sul tavolo UserProfiles, ID è già la chiave primaria e indice cluster. L'aggiunta di

[Index("CI_UserProfiles_UserID", IsClustered = true)] 

a UserID crea questa migrazione:

CreateIndex("dbo.UserProfiles", "UserID", clustered: true, name: "IX_UserProfiles_UserID"); 

Eseguendo la migrazione genera il seguente errore:

Cannot create more than one clustered index on table 'dbo.UserProfiles'. Drop the existing clustered index 'PK_dbo.UserProfiles' before creating another.

+0

Non sarebbe meglio aggiungere un indice non cluster su ID utente? Di solito avere il pk come indice cluster è il migliore. (Dal momento che è solitamente utilizzato in join, ecc.) – Magnus

+0

@Magnus non la penso così. Con l'ID GUID come indice cluster, le informazioni sul profilo degli utenti saranno sparse sul disco che richiede l'accesso al disco per ogni parte delle informazioni del profilo dell'utente. Un indice cluster sull'ID utente produrrà il recupero delle informazioni del profilo utente in un potenziale accesso a un singolo disco. –

+0

Stai dicendo che stai usando questa tabella solo per la ricerca UserId e mai con join con altre tabelle nella colonna ID? – Magnus

risposta

0

È necessario rimuovere l'indice cluster esistente dal tuo attuale PK 'ID 'che viene creato per impostazione predefinita per qualsiasi proprietà "KEY" nel codice prima. Esso può essere fatto utilizzando API fluente:

.Primarykey(x=>x.ID,clustered:false) 

indice Una volta esistente cluster viene rimosso dal ID, la migrazione per aggiungere l'indice cluster su UserID dovrebbe funzionare senza problemi.

+0

Mi manca qualcosa qui? modelBuilder.Entity () .PrimayKey (x => x.ID, clustered: false); 'System.Data.Entity.ModelConfiguration.EntityTypeConfiguration ' non contiene una definizione per 'PrimayKey' –

+0

È un refuso? Nel tuo commento non vedo "r" in PrimaryKey. –

+0

Non contiene una definizione per PrimayKey o PrimaryKey. Non riesco a trovare il metodo PrimaryKey fluente documentato ovunque. –

4

per risolvere il problema, dopo aver generato il file di migrazione, è necessario modificare il codice generato disabilitando indice cluster per la chiave primaria assegnando false come valore di parametro clusteredPrimaryKey.

Dopo le modifiche è necessario avere qualcosa di simile nel file di migrazione:

CreateTable(
    "dbo.UserProfiles", 
    c => new 
     { 
      Id = c.Guid(nullable: false), 
      UserID = c.Guid(nullable: false), 
      FieldID = c.Guid(nullable: false), 
      Value = c.String(nullable: false, maxLength: 400), 
     }) 
    .PrimaryKey(t => t.Id, clustered: false) 
    .Index(t => t.UserID, clustered: true, name: "CI_UserProfiles_UserID"); 

Questo non viene fatto in OnModelCreating metodo utilizzando API Fluent come Manish Kumar ha detto, ma in file di migrazione. Il file che viene creato quando si utilizza il comando Add-Migration.

Database

Come si dice nei commenti esistente, il database già esiste. Dopo l'esecuzione Add-Migration comando, si avrà questa riga nel file DbMigration nella Up() metodo:

public override void Up() 
{ 
    CreateIndex("dbo.UserProfiles", "UserID", clustered: true, name: "CI_UserProfiles_UserID"); 
} 

è necessario modificare il metodo Up() di avere questo codice:

public override void Up() 
{ 
    this.Sql("ALTER TABLE dbo.UserProfiles DROP CONSTRAINT \"PK_dbo.UserProfiles\""); 
    this.Sql("ALTER TABLE dbo.UserProfiles ADD CONSTRAINT \"PK_dbo.UserProfiles\" PRIMARY KEY NONCLUSTERED (Id);"); 
    this.CreateIndex("dbo.UserProfiles", "UserID", clustered: true, name: "CI_UserProfiles_UserID"); 
} 

Nel codice di cui sopra ho assunto che l'indice cluster creato è denominato PK_dbo.UserProfiles nel database. In caso contrario, inserire in questo posto il nome corretto.

+0

Questa è un'ottima soluzione se la tabella non è ancora stata distribuita in un ambiente di produzione, ma ovviamente poiché la tabella esiste già, viene visualizzato l'errore "Nel database è già presente un oggetto denominato" UserProfiles ". –

+0

Ho provato a modificare il tuo post con la soluzione completa ma i revisori hanno rifiutato la modifica. Se vuoi copiare le parti mancanti nella tua risposta, accetterò la tua risposta. @CodeNotFound –

+0

Sì, non sapevo che fosse un database esistente. Ho modificato il mio codice per seguire il tuo vincolo con una soluzione migliore e semplice. Spero ti possa aiutare. – CodeNotFound

0

Dopo aver creato il file di migrazione, modificare il codice generato, disattivando l'indice cluster per la chiave primaria impostando la proprietà cluster su false.

Essendo che Azure non consente una tabella senza un indice cluster e non esiste alcuna utilità in SQL Server per "modificare" un indice cluster su una tabella, è necessario creare una nuova tabella con l'indice cluster e migrare il dati esistenti ad esso.Il codice seguente rinomina la tabella originale, migra i dati nella nuova tabella creata con il nuovo indice cluster e rilascia la tabella originale.

 RenameTable("dbo.UserProfiles", "UserProfiles_PreMigrate"); 

     CreateTable(
      "dbo.UserProfiles", 
      c => new 
      { 
       Id = c.Guid(nullable: false), 
       UserID = c.Guid(nullable: false), 
       FieldID = c.Guid(nullable: false), 
       Value = c.String(nullable: false, maxLength: 400), 
      }) 
      .PrimaryKey(t => t.Id, clustered: false) 
      .Index(t => t.UserID, clustered: true, name: "CI_UserProfiles_UserID"); 

     Sql(@" 
      INSERT [dbo].[UserProfiles] 
      (ID, 
      UserID, 
      FieldID, 
      Value) 
      SELECT 
      ID, 
      UserID, 
      FieldID, 
      Value 
      FROM dbo.UserProfiles_PreMigrate 

     "); 

     DropTable("UserProfiles_PreMigrate"); 

eventuali vincoli di tabella esistente andrà perduto in questa operazione, quindi sarà necessario ricreare e indici, chiavi esterne, ecc sul tavolo.

+0

Ho modificato la mia risposta con una soluzione semplice senza la migrazione dei dati. – CodeNotFound

Problemi correlati