Limitazioni del provider di database SQLite per EF Core

Il provider SQLite presenta una serie di limitazioni delle migrazioni. La maggior parte di queste limitazioni è causata da limitazioni nel motore di database SQLite sottostante e non sono specifiche di ENTITY.

Limitazioni di modellazione

La libreria relazionale comune (condivisa dai provider di database relazionali di EF Core) definisce le API per la modellazione dei concetti comuni alla maggior parte dei motori di database relazionali. Un paio di questi concetti non sono supportati dal provider SQLite.

Limitazioni delle query

SQLite non supporta in modo nativo i tipi di dati seguenti. EF Core può leggere e scrivere valori di questi tipi ed è supportata anche l'esecuzione di query per verificarne l'uguaglianza (where e.Property == value). Altre operazioni, tuttavia, come il confronto e l'ordinamento richiederanno una valutazione sul client.

  • DateTimeOffset
  • decimal
  • TimeSpan
  • ulong

Anziché DateTimeOffset, è consigliabile usare valori di DateTime. Quando si gestiscono più fusi orari, è consigliabile convertire i valori in UTC prima di salvare e quindi riconvertire il fuso orario appropriato.

Il decimal tipo fornisce un livello elevato di precisione. Se non è necessario tale livello di precisione, tuttavia, è consigliabile usare double. È possibile usare un convertitore di valori per continuare a usare decimal nelle classi.

modelBuilder.Entity<MyEntity>()
    .Property(e => e.DecimalProperty)
    .HasConversion<double>();

Limitazioni delle migrazioni

Il motore di database SQLite non supporta una serie di operazioni dello schema supportate dalla maggior parte degli altri database relazionali. Se si tenta di applicare una delle operazioni non supportate a un database SQLite, verrà generata un'eccezione NotSupportedException .

Verrà tentata una ricostruzione per eseguire determinate operazioni. Le ricompilazioni sono possibili solo per gli artefatti del database che fanno parte del modello EF Core. Se un artefatto di database non fa parte del modello, ad esempio se è stato creato manualmente all'interno di una migrazione, viene comunque generata una NotSupportedException.

Operazione Supportato?
AddCheckConstraint ✔ (ricompilazione)
AddColumn
AddForeignKey ✔ (ricompilazione)
AddPrimaryKey (AggiungiChiavePrimaria) ✔ (ricompilazione)
AddUniqueConstraint ✔ (ricompilazione)
AlterColumn ✔ (ricompilazione)
CreateIndex
CreateTable
DropCheckConstraint ✔ (ricompilazione)
DropColumn ✔ (ricompilazione)
DropForeignKey ✔ (ricompilazione)
DropIndex
DropPrimaryKey ✔ (ricompilazione)
DropTable
DropUniqueConstraint ✔ (ricompilazione)
RenameColumn
RinominaIndice ✔ (ricompilazione)
RinominaTabella
EnsureSchema ✔ (nessuna operazione)
DropSchema ✔ (nessuna operazione)
Inserisci
Aggiornamento
Elimina

Soluzioni per ovviare alle limitazioni delle migrazioni

È possibile risolvere alcune di queste limitazioni scrivendo manualmente codice nelle migrazioni per eseguire una ricompilazione. Le ricompilazione delle tabelle comportano la creazione di una nuova tabella, la copia dei dati nella nuova tabella, l'eliminazione della tabella precedente, la ridenominazione della nuova tabella. Per eseguire alcuni di questi passaggi, è necessario usare il Sql metodo .

Per altri dettagli, vedere Creazione di altri tipi di modifiche dello schema di tabella nella documentazione di SQLite.

Limitazioni degli script idempotenti

A differenza di altri database, SQLite non include un linguaggio procedurale. Per questo motivo, non è possibile generare la logica if-then richiesta dagli script di migrazione idempotenti.

Se si conosce l'ultima migrazione applicata a un database, è possibile generare uno script da tale migrazione alla migrazione più recente.

dotnet ef migrations script CurrentMigration

In caso contrario, è consigliabile usare dotnet ef database update per applicare le migrazioni. È possibile specificare il file di database quando si esegue il comando .

dotnet ef database update --connection "Data Source=My.db"

Protezione delle migrazioni simultanee

EF9 ha introdotto un meccanismo di blocco della migrazione per proteggersi dalle esecuzioni simultanee della migrazione. A differenza di SQL Server, che usa un blocco dell'applicazione a livello di sessione (sp_getapplock) rilasciato automaticamente quando la connessione si chiude, SQLite non dispone di blocchi dell'applicazione predefiniti. EF Core crea invece una __EFMigrationsLock tabella e inserisce una riga per acquisire il blocco.

Gestione dei blocchi abbandonati

Se l'applicazione termina in modo imprevisto, ad esempio il processo viene terminato durante la migrazione, la riga di blocco nella __EFMigrationsLock tabella potrebbe non essere pulita. In questo modo si impedisce il completamento di qualsiasi migrazione successiva, perché ogni tentativo attenderà a tempo indeterminato il rilascio del blocco.

Per risolvere un blocco abbandonato, eliminare la __EFMigrationsLock tabella dal database:

DROP TABLE "__EFMigrationsLock";

In alternativa, eliminare tutte le righe dalla tabella:

DELETE FROM "__EFMigrationsLock";

Dopo aver cancellato il blocco, le operazioni di migrazione successive procedono normalmente. La tabella viene ricreata automaticamente in base alle esigenze.

Vedi anche