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 Entity Framework) 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.
- Schemi
- Sequenze
- Token di concorrenza generati dal database (vedere la documentazione)
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 la valutazione sul client.
- DateTimeOffset
- Decimale
- TimeSpan
- UInt64
Invece di DateTimeOffset
, è consigliabile usare i valori 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 ricompilazione per eseguire determinate operazioni. Le ricompilazione sono possibili solo per gli artefatti del database che fanno parte del modello di 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 generato un oggetto NotSupportedException
.
Operazione | Supportato? |
---|---|
AddCheckConstraint | ✔ (ricompilazione) |
AddColumn | ✔ |
AddForeignKey | ✔ (ricompilazione) |
AddPrimaryKey | ✔ (ricompilazione) |
AddUniqueConstraint | ✔ (ricompilazione) |
AlterColumn | ✔ (ricompilazione) |
CreateIndex | ✔ |
CreateTable | ✔ |
DropCheckConstraint | ✔ (ricompilazione) |
DropColumn | ✔ (ricompilazione) |
DropForeignKey | ✔ (ricompilazione) |
DropIndex | ✔ |
DropPrimaryKey | ✔ (ricompilazione) |
DropTable | ✔ |
DropUniqueConstraint | ✔ (ricompilazione) |
RenameColumn | ✔ |
RenameIndex | ✔ (ricompilazione) |
RenameTable | ✔ |
EnsureSchema | ✔ (no-op) |
DropSchema | ✔ (no-op) |
Inserisci | ✔ |
Update | ✔ |
Elimina | ✔ |
Soluzione alternativa 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(string)
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 durante l'esecuzione delle migrazioni. Mira a proteggersi da più esecuzioni di migrazione eseguite contemporaneamente, in quanto ciò potrebbe lasciare il database in uno stato danneggiato. Si tratta di uno dei potenziali problemi derivanti dall'applicazione delle migrazioni in fase di esecuzione tramite il DbContext.Database.Migrate()
metodo (vedere Applicazione delle migrazioni per altre informazioni). Per attenuare questo problema, Entity Framework crea un blocco esclusivo sul database prima dell'applicazione di qualsiasi operazione di migrazione.
Sfortunatamente, SQLite non dispone di un meccanismo di blocco predefinito, quindi EF crea una tabella separata (__EFMigrationsLock
) e la usa per il blocco. Il blocco viene rilasciato al termine della migrazione e il codice di seeding termina l'esecuzione. Tuttavia, se per qualche motivo la migrazione non riesce in modo non recuperabile, il blocco potrebbe non essere rilasciato correttamente. In questo caso, le migrazioni consecutive verranno bloccate per l'esecuzione di SQL e pertanto non verranno mai completate. È possibile sbloccarli manualmente eliminando la __EFMigrationsLock
tabella nel database.