Migrazioni Code First con un database esistente

Nota

EF4.3 Solo versioni successive: le funzionalità, le API e così via descritte in questa pagina sono state introdotte in Entity Framework 4.1. Se si usa una versione precedente, le informazioni qui riportate, o parte di esse, non sono applicabili.

Questo articolo illustra l'uso di Migrazioni Code First con un database esistente, uno non creato da Entity Framework.

Nota

Questo articolo presuppone che si sappia come usare Migrazioni Code First in scenari di base. In caso contrario, sarà necessario leggere Migrazioni Code First prima di continuare.

Passaggio 1: Creare un modello

Il primo passaggio consiste nel creare un modello Code First destinato al database esistente. L'argomento Code First in un database esistente fornisce indicazioni dettagliate su come eseguire questa operazione.

Nota

Prima di apportare modifiche al modello che richiederebbero modifiche allo schema del database, è importante seguire la parte restante dei passaggi descritti in questo argomento. I passaggi seguenti richiedono che il modello sia sincronizzato con lo schema del database.

Passaggio 2: Abilitare le migrazioni

Il passaggio successivo consiste nell'abilitare le migrazioni. A tale scopo, eseguire il comando Enable-Migrations in Gestione pacchetti Console.

Questo comando crea una cartella nella soluzione denominata Migrations e inserisce una singola classe all'interno di essa denominata Configuration. La classe Configuration è la posizione in cui si configurano le migrazioni per l'applicazione. Per altre informazioni, vedere l'argomento Migrazioni Code First.

Passaggio 3: Aggiungere una migrazione iniziale

Dopo aver creato e applicato le migrazioni al database locale, è anche possibile applicare queste modifiche ad altri database. Ad esempio, il database locale può essere un database di test e può essere utile applicare anche le modifiche a un database di produzione e/o ad altri database di test per sviluppatori. Esistono due opzioni per questo passaggio e quella da selezionare dipende dal fatto che lo schema di qualsiasi altro database sia vuoto o che corrisponda attualmente allo schema del database locale.

  • Opzione 1: usare lo schema esistente come punto di partenza. È consigliabile usare questo approccio quando altri database a cui verranno applicate le migrazioni in futuro avranno lo stesso schema del database locale. Ad esempio, è possibile usarlo se il database di test locale corrisponde attualmente alla versione 1 del database di produzione e queste migrazioni verranno applicate successivamente per aggiornare il database di produzione alla versione 2.
  • Opzione Due: usare un database vuoto come punto di partenza. È consigliabile usare questo approccio quando altri database a cui verranno applicate le migrazioni in futuro sono vuoti (o non esistono ancora). Ad esempio, è possibile usarlo se si è iniziato a sviluppare l'applicazione usando un database di test, ma senza usare le migrazioni e successivamente si vuole creare un database di produzione da zero.

Opzione 1: Usare lo schema esistente come punto di partenza

Migrazioni Code First usa uno snapshot del modello archiviato nella migrazione più recente per rilevare le modifiche apportate al modello . È possibile trovare informazioni dettagliate su questo aspetto in Migrazioni Code First in Ambienti team. Poiché si presuppone che i database abbiano già lo schema del modello corrente, verrà generata una migrazione vuota (senza operazioni) con il modello corrente come snapshot.

  1. Eseguire il comando Add-Migration InitialCreate –IgnoreChanges in Gestione pacchetti Console. Verrà creata una migrazione vuota con il modello corrente come snapshot.
  2. Eseguire il comando Update-Database nella console di Gestione pacchetti. Verrà applicata la migrazione InitialCreate al database. Poiché la migrazione effettiva non contiene modifiche, aggiungerà semplicemente una riga alla tabella __MigrationsHistory che indica che la migrazione è già stata applicata.

Opzione 2: Usare un database vuoto come punto di partenza

In questo scenario sono necessarie Migrazioni per poter creare l'intero database da zero, incluse le tabelle già presenti nel database locale. Verrà generata una migrazione InitialCreate che include la logica per creare lo schema esistente. Il database esistente sarà quindi simile a quello già applicato alla migrazione.

  1. Eseguire il comando Add-Migration InitialCreate nella console di Gestione pacchetti. Verrà creata una migrazione per creare lo schema esistente.
  2. Impostare come commento tutto il codice nel metodo Up della migrazione appena creata. Ciò consentirà di applicare la migrazione al database locale senza tentare di ricreare tutte le tabelle e così via.
  3. Eseguire il comando Update-Database nella console di Gestione pacchetti. Verrà applicata la migrazione InitialCreate al database. Poiché la migrazione effettiva non contiene modifiche (perché sono state impostate temporaneamente come commento), verrà semplicemente aggiunta una riga alla tabella __MigrationsHistory che indica che la migrazione è già stata applicata.
  4. Annullare il commento del codice nel metodo Up. Ciò significa che quando questa migrazione viene applicata ai database futuri, lo schema già esistente nel database locale verrà creato dalle migrazioni.

Aspetti da tenere presenti

Quando si usano le migrazioni in un database esistente, è necessario tenere presenti alcuni aspetti.

I nomi predefiniti/calcolati potrebbero non corrispondere allo schema esistente

Le migrazioni specificano in modo esplicito i nomi per le colonne e le tabelle quando esegue lo scaffolding di una migrazione. Esistono tuttavia altri oggetti di database per cui Le migrazioni calcolano un nome predefinito per quando si applicano le migrazioni. Sono inclusi gli indici e i vincoli di chiave esterna. Quando la destinazione è uno schema esistente, questi nomi calcolati potrebbero non corrispondere a ciò che esiste effettivamente nel database.

Ecco alcuni esempi di quando è necessario tenere presente quanto segue:

Se è stata usata l'opzione 1: usare lo schema esistente come punto di partenza del passaggio 3:

  • Se le modifiche future nel modello richiedono la modifica o l'eliminazione di uno degli oggetti di database denominati in modo diverso, sarà necessario modificare la migrazione con scaffolding per specificare il nome corretto. Le API Migrations hanno un parametro Name facoltativo che consente di eseguire questa operazione. Ad esempio, lo schema esistente può avere una tabella Post con una colonna chiave esterna BlogId con un indice denominato IndexFk_BlogId. Per impostazione predefinita, tuttavia, le migrazioni prevedono che questo indice sia denominato IX_BlogId. Se si apporta una modifica al modello che comporta l'eliminazione di questo indice, sarà necessario modificare la chiamata dropIndex con scaffolding per specificare il nome IndexFk_BlogId.

Se è stata usata l'opzione Due: Usare un database vuoto come punto di partenza nel passaggio 3:

  • Il tentativo di eseguire il metodo Down della migrazione iniziale( ovvero il ripristino di un database vuoto) sul database locale potrebbe non riuscire perché le migrazioni tenteranno di eliminare indici e vincoli di chiave esterna usando i nomi non corretti. Ciò influirà solo sul database locale perché gli altri database verranno creati da zero usando il metodo Up della migrazione iniziale. Se si vuole effettuare il downgrade del database locale esistente a uno stato vuoto, è più semplice eseguire questa operazione manualmente, eliminando il database o eliminando tutte le tabelle. Dopo questo downgrade iniziale, tutti gli oggetti di database verranno ricreati con i nomi predefiniti, quindi questo problema non si presenterà di nuovo.
  • Se le modifiche future apportate al modello richiedono la modifica o l'eliminazione di uno degli oggetti di database denominati in modo diverso, questo non funzionerà sul database locale esistente, perché i nomi non corrispondono alle impostazioni predefinite. Tuttavia, funzionerà con i database creati da zero, perché utilizzeranno i nomi predefiniti scelti dalle migrazioni. È possibile apportare queste modifiche manualmente nel database esistente locale o prendere in considerazione la possibilità di ricreare il database da zero, come in altri computer.
  • I database creati usando il metodo Up della migrazione iniziale possono differire leggermente rispetto al database locale perché verranno usati i nomi predefiniti calcolati per gli indici e i vincoli di chiave esterna. È anche possibile che si verifichino indici aggiuntivi perché le migrazioni creeranno indici nelle colonne di chiave esterna per impostazione predefinita. Questo potrebbe non essere stato il caso nel database locale originale.

Non tutti gli oggetti di database sono rappresentati nel modello

Gli oggetti di database che non fanno parte del modello non verranno gestiti dalle migrazioni. Ciò può includere viste, stored procedure, autorizzazioni, tabelle che non fanno parte del modello, indici aggiuntivi e così via.

Ecco alcuni esempi di quando è necessario tenere presente quanto segue:

  • Indipendentemente dall'opzione scelta nel passaggio 3, se le modifiche future nel modello richiedono la modifica o l'eliminazione di questi oggetti aggiuntivi, le migrazioni non sapranno apportare queste modifiche. Ad esempio, se si elimina una colonna con un indice aggiuntivo, Le migrazioni non sapranno eliminare l'indice. Sarà necessario aggiungerlo manualmente alla migrazione con scaffolding.
  • Se è stata usata l'opzione Due: usare un database vuoto come punto di partenza, questi oggetti aggiuntivi non verranno creati dal metodo Up della migrazione iniziale. È possibile modificare i metodi Up e Down per prendersi cura di questi oggetti aggiuntivi, se lo si desidera. Per gli oggetti non supportati in modo nativo nell'API Migrazioni, ad esempio le viste, è possibile usare il metodo Sql per eseguire SQL non elaborato per crearli o eliminarli.