Gestione delle migrazioni
Man mano che il modello cambia, le migrazioni vengono aggiunte e rimosse durante lo sviluppo normale e i file di migrazione vengono controllati 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 aver modificato il 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 principale delle migrazioni. Contiene le operazioni necessarie per applicare la migrazione (in
Up
) e per ripristinarla (inDown
). - 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
È anche possibile modificare lo spazio dei nomi indipendentemente dalla directory usando --namespace
.
Personalizzare il codice di migrazione
Mentre 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 è la ridenominazione di 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 in genere non è in grado di sapere quando l'intenzione è eliminare una colonna e crearne una nuova (due modifiche separate) e quando una colonna deve essere rinominata. Se la migrazione precedente viene applicata così come è, tutti i nomi dei clienti andranno 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, ciò causerebbe una perdita di dati indesiderata. Per trasferire i dati dalle colonne precedenti, vengono 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 alcuna modifica al modello; verrà generata una migrazione vuota, che sarà quindi possibile popolare con operazioni SQL non elaborate.
Ad esempio, la migrazione seguente crea una stored procedure di 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 una sola in un batch SQL. Può anche essere usato 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.
Può essere usato 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 esplicitamente la transazione passando suppressTransaction: true
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 eventuali migrazioni già applicate ai database di produzione. In questo modo non sarà possibile ripristinare tali migrazioni dai database e potrebbe interrompere i presupposti effettuati dalle migrazioni successive.
Elenco delle migrazioni
È possibile elencare tutte le migrazioni esistenti come indicato di seguito:
dotnet ef migrations list
Controllo delle modifiche al modello in sospeso
Nota
Questa funzionalità è stata aggiunta in EF Core 8.0.
In alcuni casi potrebbe essere necessario verificare se sono state apportate modifiche al modello dall'ultima migrazione. Ciò può aiutare a sapere quando si è dimenticato di aggiungere una migrazione da parte di un collega o di un collega. Un modo per eseguire questa operazione consiste nell'usare questo comando.
dotnet ef migrations has-pending-model-changes
È anche possibile eseguire questo controllo a livello di codice usando context.Database.HasPendingModelChanges()
. Può essere usato per scrivere uno unit test che non riesce quando si dimentica di aggiungere una migrazione.
Reimpostazione di tutte le migrazioni
In alcuni casi estremi potrebbe essere necessario rimuovere tutte le migrazioni e ricominciare. Questa operazione può essere eseguita facilmente eliminando la cartella Migrations e rilasciando 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. Questa operazione è talvolta denominata "squashing" e comporta alcune operazioni manuali:
- Eseguire il backup del database, nel caso in cui si sia verificato un errore.
- Nel database eliminare tutte le righe dalla tabella della cronologia delle migrazioni, ad esempio
DELETE FROM [__EFMigrationsHistory]
in SQL Server. - Eliminare la cartella Migrations .
- Creare una nuova migrazione e generare uno script SQL (
dotnet ef migrations script
). - Inserire una singola riga nella cronologia delle migrazioni per registrare che la prima migrazione è già stata applicata, poiché le tabelle sono già presenti. L'istruzione SQL di inserimento è l'ultima operazione nello script SQL generato in precedenza e è simile alla seguente (non dimenticare di aggiornare i valori):
INSERT INTO [__EFMigrationsHistory] ([MIGRATIONID], [PRODUCTVERSION])
VALUES (N'<full_migration_timestamp_and_name>', N'<EF_version>');
Avviso
Qualsiasi codice di migrazione personalizzato andrà perso quando la cartella Migrations viene eliminata. Per conservare le eventuali personalizzazioni, è necessario applicare manualmente la nuova migrazione iniziale.
Risorse aggiuntive
- Informazioni di riferimento sugli strumenti di Entity Framework Core - Interfaccia della riga di comando di .NET Core: include i comandi per aggiornare, eliminare, aggiungere, rimuovere e altro ancora.
- Informazioni di riferimento sugli strumenti di Entity Framework Core - Console di Gestione pacchetti in Visual Studio: include i comandi per aggiornare, eliminare, aggiungere, rimuovere e altro ancora.