Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
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 .
Tip
Se il DbContext si trova in un assembly diverso rispetto al progetto di avvio, è possibile specificare in modo esplicito i progetti di destinazione e avvio negli strumenti della Console di Gestione pacchetti o negli strumenti .NET CLI.
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 un messaggio di commit in un sistema di controllo della versione. Ad esempio, è possibile scegliere un nome come AddBlogCreatedTimestamp se la modifica è una nuova proprietà CreatedTimestamp nell'entità Blog.
Tre file sono stati aggiunti al progetto nella directory Migrations:
-
XXXXXXXXXXXXXX_AddBlogCreatedTimestamp.cs: file delle migrazioni principale. Contiene le operazioni necessarie per applicare la migrazione (in
Up) e per ripristinarla (inDown). - XXXXXXXXXXXXXX_AddBlogCreatedTimestamp.Designer.cs--File di metadati delle migrazioni. Contiene informazioni usate da Entity Framework.
- MyContextModelSnapshot.cs--Uno snapshot del modello corrente. Usato per determinare le modifiche apportate durante l'aggiunta della migrazione successiva.
Il timestamp nel nome file consente di mantenerli ordinati in ordine cronologico in modo da visualizzare la progressione delle modifiche.
Namespaces
Avete la libertà di spostare manualmente i file delle migrazioni e modificarne lo spazio dei nomi. Le nuove migrazioni vengono create come migrazioni di pari livello rispetto all'ultima migrazione. In alternativa, è possibile specificare la directory in fase di generazione come indicato di seguito:
dotnet ef migrations add InitialCreate --output-dir Your/Directory
Note
È anche possibile modificare lo spazio dei nomi indipendentemente dalla directory usando --namespace.
Creare e applicare una migrazione in un unico passaggio
Note
Questa funzionalità è stata aggiunta in EF Core 11.
Il dotnet ef database update comando supporta la creazione e l'applicazione di una migrazione in un singolo passaggio usando l'opzione --add . Questo usa Roslyn per compilare la migrazione in fase di esecuzione, abilitando scenari come .NET Aspire e applicazioni in contenitori in cui l'applicazione non può essere arrestata e ricompilata:
dotnet ef database update InitialCreate --add
È possibile usare le stesse opzioni disponibili per dotnet ef migrations add :
dotnet ef database update AddProducts --add --output-dir Migrations/Products --namespace MyApp.Migrations
Questo comando esegue lo scaffolding di una nuova migrazione con il nome specificato, lo compila usando Roslyn e lo applica immediatamente al database. I file di migrazione vengono ancora salvati su disco per il controllo del codice sorgente e la ricompilazione futura.
Se non vengono rilevate modifiche al modello in sospeso, il comando applica eventuali migrazioni in sospeso esistenti senza crearne una nuova.
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 delle colonne
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 as-is, 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");
Tip
Il processo di scaffolding della migrazione avvisa quando un'operazione potrebbe comportare una perdita di dati, ad esempio l'eliminazione di una colonna. Se viene visualizzato l'avviso, assicurarsi in particolare di esaminare il codice delle migrazioni per verificare l'accuratezza.
Operazioni sui dati
Le migrazioni possono spostare i dati e modificare lo schema. Scegliere l'operazione in base al fatto che i valori siano noti quando viene scritta la migrazione:
- Usare
InsertData,UpdateDataeDeleteDataper i valori fissi e le righe identificate da chiavi esplicite. EF Core converte queste operazioni in SQL specifico del provider, quindi funzionano anche durante la generazione di script e bundle. - Utilizzare
Sqlquando i nuovi valori devono essere calcolati dai dati del database esistenti. La sintassi SQL può differire in base al provider; diramazione suMigrationBuilder.ActiveProviderquando necessario. - Definire un'operazione di migrazione personalizzata quando un'operazione riutilizzabile richiede una generazione SQL specifica del provider.
Non usare i tipi CLR correnti DbContext o di entità per spostare i dati in una migrazione. Le migrazioni cronologiche devono continuare a compilare e comportarsi allo stesso modo dopo la modifica o la rimozione di tali tipi.
Trasformare i dati esistenti
Quando si sostituiscono le colonne, mantenere i dati di origine fino a quando non viene popolata la destinazione:
- Aggiungere la colonna di destinazione come nullable.
- Popolarlo dalle colonne esistenti.
- Se necessario, impostare la colonna di destinazione.
- Eliminare le colonne di origine.
La migrazione seguente implementa tale sequenza per SQL Server e SQLite:
migrationBuilder.AddColumn<string>(
name: "FullName",
table: "Customers",
nullable: true);
if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer")
{
migrationBuilder.Sql(
"""
UPDATE [Customers]
SET [FullName] = [FirstName] + N' ' + [LastName];
""");
}
else if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite")
{
migrationBuilder.Sql(
"""
UPDATE "Customers"
SET "FullName" = "FirstName" || ' ' || "LastName";
""");
}
else
{
throw new NotSupportedException(
$"Data migration is not implemented for provider {migrationBuilder.ActiveProvider}.");
}
migrationBuilder.AlterColumn<string>(
name: "FullName",
table: "Customers",
nullable: false,
oldClrType: typeof(string),
oldNullable: true);
migrationBuilder.DropColumn(
name: "FirstName",
table: "Customers");
migrationBuilder.DropColumn(
name: "LastName",
table: "Customers");
Aggiungere un ramo per ogni provider supportato dall'applicazione. La creazione di un provider sconosciuto è più sicura rispetto all'applicazione invisibile all'utente di una migrazione incompleta. Non compilare SQL da valori non attendibili; la migrazione di SQL viene eseguita con privilegi di modifica dello schema.
Alcune trasformazioni non possono essere invertite senza perdere informazioni. Implementare Down solo quando i valori originali possono essere ricostruiti in modo sicuro. In caso contrario, non eseguire in modo esplicito e richiedere il ripristino dei dati da un backup come parte della procedura di rollback.
Inserire dati fissi
Usare InsertData quando le chiavi e i valori sono noti quando viene scritta la migrazione:
migrationBuilder.InsertData(
table: "Countries",
columns: new[] { "CountryId", "Name" },
values: new object[,]
{
{ 1, "United States" },
{ 2, "Canada" }
});
Il metodo corrispondente Down deve chiamare DeleteData con le stesse chiavi.
Aggiornare i dati fissi
UpdateData identifica una riga in base alla chiave e imposta una o più colonne su valori fissi:
migrationBuilder.UpdateData(
table: "Countries",
keyColumn: "CountryId",
keyValue: 1,
column: "Name",
value: "United States of America");
Il Down metodo deve ripristinare i valori precedenti.
Eliminare i dati fissi
DeleteData identifica anche le righe in base alla chiave:
migrationBuilder.DeleteData(
table: "Countries",
keyColumn: "CountryId",
keyValue: 2);
Se l'eliminazione deve essere reversibile, il Down metodo deve usare InsertData per ripristinare ogni valore eliminato. Queste operazioni non eseguono query sullo stato corrente del database; usare Sql o inizializzare il seeding in fase di inizializzazione quando il comportamento dipende dai dati esistenti.
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
SELECT @LastName + @FirstName;')");
Tip
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:
- Procedure memorizzate
- Ricerca testo integrale
- Functions
- Triggers
- Views
Nella maggior parte dei casi, EF Core racchiude automaticamente 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.
Note
In EF Core 9 EF Core si estende su tutte le migrazioni in sospeso con una singola transazione per impostazione predefinita(questa operazione è stata ripristinata in EF Core 10). Per informazioni dettagliate, vedere la nota di modifica che causa un'interruzione .
Rimuovere una migrazione
A volte si aggiunge una migrazione e ci si rende conto che è necessario apportare altre modifiche al modello di EF Core prima di applicarla. Per rimuovere l'ultima migrazione, usare questo comando.
dotnet ef migrations remove
Dopo aver rimosso la migrazione, è possibile apportare le modifiche aggiuntive del modello e aggiungerlo di nuovo.
Warning
Evitare di rimuovere eventuali migrazioni già applicate ai database di produzione. In questo modo non sarà possibile ripristinare tali migrazioni nei database e potrebbe compromettere i presupposti fatti dalle migrazioni successive.
Se la migrazione è stata applicata localmente
Per un database di sviluppo eliminabile, aggiornare prima il database alla migrazione precedente e quindi rimuovere la migrazione dal progetto. Usare 0 come destinazione quando si rimuove la prima migrazione.
dotnet ef database update PreviousMigration
dotnet ef migrations remove
In alternativa, --force esegue entrambi i passaggi:
dotnet ef migrations remove --force
Se la migrazione è stata applicata a un database condiviso
Non eliminare una migrazione applicata a un database condiviso, di test o di produzione. In genere, mantenere la migrazione nel progetto e aggiungere una nuova migrazione correttiva. Se è necessario un rollback pianificato, eseguire il rollback mentre il codice di migrazione originale è ancora disponibile e coordinare la distribuzione dell'applicazione e del database.
Rimuovere una migrazione non applicata precedente
Gli strumenti rimuovono solo la migrazione più recente. Non eliminare una migrazione dal centro della sequenza e modificare a mano lo snapshot del modello. Se la migrazione e ogni migrazione dopo la pubblicazione e l'annullamento dell'applicazione, rimuovere le migrazioni successive in ordine inverso, rimuovere la migrazione indesiderata e quindi eseguire di nuovo lo scaffolding delle modifiche del modello mantenute.
Se le migrazioni sono state create in rami diversi, seguire invece il flusso di lavoro dell'albero di migrazione divergente .
Elenco delle migrazioni
È possibile elencare tutte le migrazioni esistenti come indicato di seguito:
dotnet ef migrations list
È anche possibile controllare lo stato della migrazione a livello di codice:
var allMigrations = context.Database.GetMigrations();
var appliedMigrations = await context.Database.GetAppliedMigrationsAsync();
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
GetPendingMigrationsAsync confronta le migrazioni nell'assembly delle migrazioni configurate con le migrazioni registrate nel database di destinazione. Non rileva le modifiche del modello che non sono state acquisite in una migrazione; usare il controllo delle modifiche del modello in sospeso sotto.
Controllo delle modifiche al modello in sospeso
Note
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. Questo può aiutarti a sapere quando tu o un compagno di squadra vi siete dimenticati di aggiungere una migrazione. 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 un test unità che fallisce se si dimentica di aggiungere una migrazione.
Note
A partire da EF Core 9, la chiamata di Migrate o MigrateAsync in presenza di modifiche al modello in sospeso genera un'eccezione (ID evento PendingModelChangesWarning). Per ulteriori informazioni, consultare la documentazione sull'applicazione delle migrazioni e la nota sulla modifica non retrocompatibile.
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. Si tratta di migrazioni di squash e comporta un lavoro manuale. EF Core attualmente non fornisce un comando di squash automatizzato; vedere dotnet/efcore#2174.
- 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. - Elimina la cartella Migrations.
- Creare una nuova migrazione e generarne 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>');
Warning
Qualsiasi codice di migrazione personalizzato andrà perso quando viene eliminata la cartella Migrazioni. Per conservare le eventuali personalizzazioni, è necessario applicare manualmente la nuova migrazione iniziale.
Prima di eseguire lo squash, verificare che ogni database distribuito sia in corrispondenza di una migrazione nota e di eseguirne il backup. È necessario creare nuovi database dalla nuova migrazione iniziale, mentre i database esistenti devono avere registrato la migrazione sostitutiva senza eseguire operazioni dello schema già applicate. Testare entrambi i percorsi prima della distribuzione.
Risorse aggiuntive
- Informazioni di riferimento sugli strumenti di Entity Framework Core - Interfaccia della riga di comando .NET : include 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: Comprende i comandi per aggiornare, eliminare, aggiungere, rimuovere e altro ancora.