Gestione delle migrazioni

Man mano che il modello cambia, le migrazioni vengono aggiunte e rimosse come parte della normale fase di sviluppo e i file di migrazione vengono archiviati nel controllo del codice sorgente del progetto. Per gestire le migrazioni, è prima necessario installare gli strumenti da riga di comando di EF Core.

Suggerimento

Se DbContext si trova in un assembly diverso da quello del progetto di avvio, è possibile specificare in modo esplicito i progetti di destinazione e di avvio negli strumenti della console di Gestione pacchetti o negli strumenti dell'interfaccia della riga di comando di .NET Core.

Aggiungere una migrazione

Dopo la modifica del modello, è possibile aggiungere una migrazione per tale modifica:

dotnet ef migrations add AddBlogCreatedTimestamp

Il nome della migrazione può essere usato come messaggio di commit in un sistema di controllo della versione. Ad esempio, è possibile scegliere un nome come AddBlogCreatedTimestamp se la modifica è una nuova CreatedTimestamp proprietà nell'entità Blog .

Nella directory Migrations del progetto vengono aggiunti tre file:

  • XXXXXXXXXXXXXX_AddCreatedTimestamp.cs--File di migrazione principale. Contiene le operazioni necessarie per applicare la migrazione (in Up) e per ripristinarla (in Down).
  • XXXXXXXXXXXXXX_AddCreatedTimestamp.Designer.cs--File di metadati delle migrazioni. Contiene informazioni usate da Entity Framework.
  • MyContextModelSnapshot.cs: snapshot del modello corrente. Usato per determinare cosa è stato modificato durante l'aggiunta della migrazione successiva.

Il timestamp nel nome file consente di mantenerne l'ordine cronologico e di visualizzare quindi la successione delle modifiche.

Spazi dei nomi

È consentito spostare i file della cartella Migrations e modificarne lo spazio dei nomi manualmente. Le nuove migrazioni vengono create come migrazioni di pari livello rispetto all'ultima. In alternativa, è possibile specificare la directory in fase di generazione come indicato di seguito:

dotnet ef migrations add InitialCreate --output-dir Your/Directory

Nota

In EF Core 5.0 è anche possibile modificare lo spazio dei nomi indipendentemente dalla directory usando --namespace.

Personalizzare il codice di migrazione

Anche se EF Core crea in genere migrazioni accurate, è consigliabile esaminare sempre il codice e assicurarsi che corrisponda alla modifica desiderata; in alcuni casi, è anche necessario farlo.

Rinomina la colonna

Un esempio importante in cui è necessaria la personalizzazione delle migrazioni è quando si ridenomina una proprietà. Ad esempio, se si rinomina una proprietà da Name a FullName, EF Core genererà la migrazione seguente:

migrationBuilder.DropColumn(
    name: "Name",
    table: "Customers");

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customers",
    nullable: true);

EF Core non è in genere in grado di sapere quando l'intenzione consiste nell'eliminare una colonna e crearne una nuova (due modifiche separate) e quando una colonna deve essere rinominata. Se la migrazione precedente viene applicata come è, tutti i nomi dei clienti verranno persi. Per rinominare una colonna, sostituire la migrazione generata in precedenza con quanto segue:

migrationBuilder.RenameColumn(
    name: "Name",
    table: "Customers",
    newName: "FullName");

Suggerimento

Durante il processo di scaffolding della migrazione viene visualizzato un avviso se un'operazione può causare una perdita di dati, ad esempio nel caso della rimozione di una colonna. Se viene visualizzato questo avviso, assicurarsi in particolare di esaminare il codice delle migrazioni per verificarne l'accuratezza.

Aggiunta di SQL non elaborato

Anche se la ridenominazione di una colonna può essere ottenuta tramite un'API predefinita, in molti casi non è possibile. Ad esempio, è possibile sostituire le proprietà esistenti FirstName e LastName con una singola proprietà, nuova FullName . La migrazione generata da EF Core sarà la seguente:

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customer",
    nullable: true);

Come in precedenza, questo causerebbe la perdita di dati indesiderata. Per trasferire i dati dalle colonne precedenti, riorganizzare le migrazioni e introdurre un'operazione SQL non elaborata come indicato di seguito:

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customer",
    nullable: true);

migrationBuilder.Sql(
@"
    UPDATE Customer
    SET FullName = FirstName + ' ' + LastName;
");

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

Modifiche arbitrarie tramite SQL non elaborato

SQL non elaborato può essere usato anche per gestire gli oggetti di database di cui EF Core non è a conoscenza. A tale scopo, aggiungere una migrazione senza apportare modifiche al modello; verrà generata una migrazione vuota, che è quindi possibile popolare con operazioni SQL non elaborate.

Ad esempio, la migrazione seguente crea una stored procedure SQL Server:

migrationBuilder.Sql(
@"
    EXEC ('CREATE PROCEDURE getFullName
        @LastName nvarchar(50),
        @FirstName nvarchar(50)
    AS
        RETURN @LastName + @FirstName;')");

Suggerimento

EXEC viene usato quando un'istruzione deve essere la prima o solo una in un batch SQL. Può essere usato anche per risolvere gli errori del parser negli script di migrazione idempotenti che possono verificarsi quando le colonne a cui si fa riferimento non esistono attualmente in una tabella.

Questa operazione può essere usata per gestire qualsiasi aspetto del database, tra cui:

  • Stored procedure
  • Ricerca full-text
  • Funzioni
  • Trigger
  • Visualizzazioni

Nella maggior parte dei casi, EF Core esegue automaticamente il wrapping di ogni migrazione nella propria transazione quando si applicano le migrazioni. Sfortunatamente, alcune operazioni di migrazione non possono essere eseguite all'interno di una transazione in alcuni database; per questi casi, è possibile rifiutare suppressTransaction: true esplicitamente la transazione passando a migrationBuilder.Sql.

Rimuovere una migrazione

Dopo l'aggiunta di una migrazione ci si rende talvolta conto che prima di applicarla sono necessarie altre modifiche al modello di Entity Framework Core. Per rimuovere l'ultima migrazione, usare questo comando.

dotnet ef migrations remove

Dopo la rimozione della migrazione, è possibile apportare le modifiche aggiuntive al modello. La migrazione può quindi essere aggiunta di nuovo.

Avviso

Evitare di rimuovere tutte le migrazioni già applicate ai database di produzione. Ciò significa che non sarà possibile ripristinare tali migrazioni dai database e potrebbe interrompere i presupposti effettuati dalle migrazioni successive.

Elencare le migrazioni

È possibile elencare tutte le migrazioni esistenti come indicato di seguito:

dotnet ef migrations list

Reimpostazione di tutte le migrazioni

In alcuni casi estremi, potrebbe essere necessario rimuovere tutte le migrazioni e iniziare. Questa operazione può essere eseguita facilmente eliminando la cartella Migrations e eliminando il database; a questo punto è possibile creare una nuova migrazione iniziale, che conterrà l'intero schema corrente.

È anche possibile reimpostare tutte le migrazioni e crearne una singola senza perdere i dati. Questo è talvolta chiamato "squashing" e implica un lavoro manuale:

  • Eliminare la cartella Migrations
  • Creare una nuova migrazione e generare uno script SQL per esso
  • Nel database eliminare tutte le righe dalla tabella cronologia delle migrazioni
  • Inserire una singola riga nella cronologia delle migrazioni per registrare che la prima migrazione è già stata applicata, poiché le tabelle sono già presenti. L'inserimento SQL è l'ultima operazione nello script SQL generato in precedenza.

Avviso

Qualsiasi codice di migrazione personalizzato verrà perso quando la cartella Migrations viene eliminata. Le personalizzazioni devono essere applicate manualmente alla nuova migrazione iniziale per essere mantenute.

Risorse aggiuntive