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.
Questa pagina illustra le modifiche di comportamento e API che potrebbero interrompere l'aggiornamento delle applicazioni esistenti da EF Core 10 a EF Core 11. Assicurarsi di esaminare le modifiche di rilievo precedenti se si esegue l'aggiornamento da una versione precedente di EF Core:
- Modifiche di rilievo in EF Core 10
- Cambiamenti rilevanti in EF Core 9
- Modifiche importanti in EF Core 8
Riassunto
Annotazioni
Se si usa Microsoft.Data.Sqlite, vedere la sezione distinta riportata di seguito relativa alle modifiche dirompenti in Microsoft.Data.Sqlite.
Modifiche ad alto impatto
Cosmos: le proprietà non mappate non vengono più mantenute
Problema di rilevamento n. 5421
Comportamento precedente
In precedenza, quando EF Core legge un documento di Cosmos DB che conteneva proprietà JSON non mappate nel modello EF, tali proprietà aggiuntive sono state mantenute nella __jObject proprietà shadow e riscritto nel database nel successivo SaveChanges. I dati non mappati nei documenti sono stati arrotondati in modo trasparente.
Nuovo comportamento
A partire da EF Core 11, le proprietà JSON non mappate in un documento di Cosmos DB vengono ignorate durante la lettura. Eventuali proprietà aggiuntive che non fanno parte del modello di Entity Framework andranno perse se l'entità viene salvata successivamente.
Perché
Poiché __jObject è stato rimosso (vedere Cosmos: __jObject proprietà shadow rimossa; JObject non è più usato per la serializzazione, non esiste alcun meccanismo per mantenere le proprietà non mappate. EF Core 11 usa un lettore JSON snella che elabora solo le proprietà che conosce dal modello.
Mitigazioni
Se l'applicazione si basa sul mantenimento dei dati non mappati, considerare una delle opzioni seguenti:
-
Usare
CosmosClientdirettamente per i documenti in cui è necessario il controllo completo sulla forma JSON. - Eseguire il mapping di tutte le proprietà pertinenti in modo esplicito nel modello di Entity Framework, inclusi tutti i campi aggiuntivi che devono essere mantenuti.
Modifiche a impatto medio
L'I/O di sincronizzazione tramite il provider di Azure Cosmos DB è stata completamente rimossa
Problema di rilevamento n. 37059
Comportamento precedente
L'I/O sincrono tramite il provider di Azure Cosmos DB non è supportato a partire da EF 9.0 (note); chiamando qualsiasi API di I/O sincrona, ad esempio ToList o SaveChanges ha generato un'eccezione, a meno che non sia stato configurato un consenso esplicito speciale. Quando è stato configurato l'opt-in, le API di I/O sincrone hanno funzionato come in precedenza, causando il blocco di tipo "sync-over-async" sull'SDK di Azure Cosmos DB, che potrebbe portare a deadlock e altri problemi di prestazioni.
Nuovo comportamento
A partire da EF Core 11.0, EF ora genera sempre quando viene chiamata un'API di I/O sincrona. Non è possibile tornare a utilizzare le API di I/O di sincronizzazione.
Perché
Il blocco sincrono sui metodi asincroni ("sincrono su asincrono") è altamente sconsigliato e può causare deadlock e altri problemi di prestazione. Poiché l'SDK di Azure Cosmos DB supporta solo metodi asincroni, anche il provider EF Cosmos fa lo stesso.
Mitigazioni
Convertire il codice in modo da usare api di I/O asincrone invece di sincronizzare quelle di I/O. Ad esempio, sostituire le chiamate a SaveChanges() con await SaveChangesAsync().
Microsoft. Data.SqlClient è stato aggiornato alla versione 7.0
Comportamento precedente
EF Core 10 ha usato Microsoft. Data.SqlClient 6.x, che includeva dipendenze di autenticazione Azure/Entra ID (ad esempio Azure.Core, Azure.Identity e Microsoft.Identity.Client) nel pacchetto principale.
Nuovo comportamento
EF Core 11 dipende ora da Microsoft. Data.SqlClient 7.0. Questa versione rimuove le dipendenze di autenticazione Azure/Entra ID (in precedenza Azure Active Directory) dal pacchetto principale. Se l'applicazione usa l'autenticazione Entra ID (ad esempio, ActiveDirectoryDefault, ActiveDirectoryInteractive, ActiveDirectoryManagedIdentity o ActiveDirectoryServicePrincipal), è ora necessario installare il pacchetto Microsoft.Data.SqlClient.Extensions.Azure separatamente.
Inoltre, SqlAuthenticationMethod.ActiveDirectoryPassword è stato contrassegnato come obsoleto.
Per altri dettagli, vedere le note sulla versione di Microsoft.Data.SqlClient 7.0.
Perché
Questa modifica è stata apportata in Microsoft. Data.SqlClient per ridurre il blob delle dipendenze per le applicazioni che non usano l'autenticazione Azure, particolarmente utile per le distribuzioni in contenitori e lo sviluppo locale.
Mitigazioni
Se l'applicazione usa l'autenticazione Entra ID con SQL Server, aggiungere un riferimento al pacchetto Microsoft.Data.SqlClient.Extensions.Azure nel progetto:
<PackageReference Include="Microsoft.Data.SqlClient.Extensions.Azure" Version="7.0.0" />
Non sono necessarie modifiche al codice oltre all'aggiunta di questo riferimento al pacchetto. Se si usa SqlAuthenticationMethod.ActiveDirectoryPassword, eseguire la migrazione a un metodo di autenticazione moderno, ActiveDirectoryDefault ad esempio o ActiveDirectoryInteractive.
Cosmos: i caratteri non validi id non vengono più sottoposti a escape
Problema di rilevamento n. 38244
Comportamento precedente
In precedenza, quando veniva generato il valore della proprietà Cosmos id da una chiave composita contenente più parti, il provider Azure Cosmos DB eseguiva l'escape di alcuni caratteri non consentiti nei valori id delle risorse Cosmos:
| Personaggio | Con escape come |
|---|---|
/ |
^2F |
\ |
^5C |
? |
^3F |
# |
^23 |
Nuovo comportamento
A partire da EF Core 11.0, questi caratteri non sono più preceduti da un carattere di escape nel valore id generato. Il id valore conterrà i valori della chiave non elaborata senza alcuna modifica. Si noti che quando vengono concatenati i valori id (ad esempio, quando si usa una chiave composita o quando si attiva il comportamento discriminator-in-id), il carattere | viene usato come separatore e tutti i caratteri | già presenti nei valori della chiave sono sottoposti a escape per evitare ambiguità. Non viene applicata alcuna altra escape.
Il comportamento di escape precedente può essere riabilitato impostando un'opzione AppContext :
AppContext.SetSwitch("Microsoft.EntityFrameworkCore.EscapeIllegalCosmosIdCharacters", true);
Perché
Il precedente meccanismo di escape non era iniettivo: il carattere di escape ^ non veniva mai sottoposto a escape. Questo significava che un valore chiave contenente la stringa letterale ^2F avrebbe prodotto lo stesso id di un valore chiave contenente /, causando una corruzione silenziosa dei dati per cui due entità con chiavi primarie distinte sarebbero state mappate allo stesso documento Cosmos. Disattivare completamente l'escape risolve il problema di collisione.
Mitigazioni
Se l'applicazione usa chiavi composite i cui valori possono contenere i caratteri /, \, ?o #, tenere presente quanto segue:
-
Dati esistenti: i documenti archiviati in precedenza in Cosmos DB hanno
idvalori usando le sequenze di escape precedenti ( ad esempioPost|1|^2F). Dopo l'aggiornamento a EF Core 11, EF genererà valori senza caratteri di escapeid(ad esempioPost|1|/) e non troverà più i documenti esistenti. Per continuare ad accedere ai dati esistenti senza migrazione, torna al comportamento precedente usando l'opzioneAppContextdescritta sopra; tuttavia, tieni presente che il bug di collisione degli ID sarà ancora presente. -
Nuovi dati: se si sta creando una nuova applicazione o un nuovo database, evitare di usare questi caratteri non validi nei valori chiave, perché non sono validi nei valori delle risorse
iddi Cosmos DB. Per informazioni dettagliate, vedere la documentazione Azure.
Cosmos: eccezione generata quando una proiezione restituisce un valore non definito
Problema di rilevamento n. 34067
Comportamento precedente
In precedenza, quando si proiettano proprietà in proiezioni di tipo anonimo o DTO tramite lo spostamento sulle relazioni facoltative in cui un segmento del percorso era assente nel documento cosmos DB (causando il valore proiettato come undefined), il comportamento era incoerente:
- Con il tipo anonimo a proprietà singola o le proiezioni DTO, EF ha convertito la query usando
SELECT VALUE, che ha filtrato automaticamente tutti i documenti in cui il valore proiettato eraundefined. Ciò significa che sono stati restituiti meno risultati del previsto, senza alcuna indicazione dei dati mancanti. - Con il tipo anonimo multiproprietà o le proiezioni DTO, è stato generato un oggetto
InvalidOperationExceptioncon il messaggio "L'oggetto nullable deve avere un valore".
Ad esempio, dato un'entità Entity con una proprietà Associate facoltativa che a sua volta ha un proprietario NestedAssociatefacoltativo:
// Previously silently returned fewer results (undefined results were filtered out)
var singlePropResults = await context.Entities
.Select(x => new { x.Associate!.NestedAssociate!.Id })
.ToListAsync();
// Previously threw InvalidOperationException: Nullable object must have a value
var multiPropResults = await context.Entities
.Select(x => new { x.Associate!.NestedAssociate!.Id, x.Associate!.NestedAssociate!.String })
.ToListAsync();
Nuovo comportamento
A partire da EF Core 11.0, viene generata un'eccezione InvalidOperationException in entrambi i casi quando una parte della proiezione restituisce undefined in Azure Cosmos DB. Il messaggio di eccezione è:
Una parte della proiezione non è stata definita, usare l'operatore coalesce per gestire i possibili valori non definiti.
Perché
Il comportamento precedente era incoerente. Le proiezioni a singola proprietà potrebbero eliminare automaticamente i risultati, rendendo più semplice perdere i dati senza alcuna indicazione del problema. Il nuovo comportamento garantisce una segnalazione degli errori coerente e prevedibile ogni volta che una proiezione rileva un valore non definito.
Mitigazioni
Usare IsDefined per filtrare i documenti in cui manca il valore proiettato:
var results = await context.Entities
.Where(x => EF.Functions.IsDefined(x.Associate!.NestedAssociate!.Id))
.Select(x => new { x.Associate!.NestedAssociate!.Id })
.ToListAsync();
In alternativa, usare CoalesceUndefined per fornire un valore predefinito per le proprietà che potrebbero essere undefined:
var results = await context.Entities
.Select(x => new
{
Id = EF.Functions.CoalesceUndefined(x.Associate!.NestedAssociate!.Id, Guid.Empty)
})
.ToListAsync();
Modifiche a basso impatto
Cosmos: __jObject proprietà shadow rimossa; JObject non più usato per la serializzazione
Problema di rilevamento n. 5421
Comportamento precedente
In precedenza, il provider di Azure Cosmos DB ha aggiunto una proprietà shadow denominata "__jObject" di tipo JObject (da Newtonsoft.Json) a ogni tipo di entità. Questa proprietà conteneva il documento JSON non elaborato ricevuto e inviato a Cosmos DB, consentendo l'accesso a dati non mappati o non elaborati:
var order = await context.Orders.FirstAsync();
var rawJson = context.Entry(order).Property<JObject>("__jObject").CurrentValue;
var billingAddress = rawJson["BillingAddress"]?.Value<string>();
EF Core usato Newtonsoft.Json (tramite JObject) internamente per tutta la serializzazione e la deserializzazione dei documenti.
Nuovo comportamento
A partire da EF Core 11, la __jObject proprietà shadow non esiste più. EF Core ora usa System.Text.Json (Utf8JsonWriterUtf8JsonReader/) per la serializzazione e la deserializzazione dei documenti e non dipende più da .Newtonsoft.Json
L'accesso alla "__jObject" proprietà genererà un'eccezione InvalidOperationException.
Perché
L'approccio JObjectbasato su richiedeva un miglioramento delle prestazioni limitato e una Newtonsoft.Json dipendenza. Il passaggio a System.Text.Json allinea EF Core Cosmos al resto dell'ecosistema .NET e consente miglioramenti significativi delle prestazioni nel materializzatore.
Mitigazioni
Per accedere al documento JSON non elaborato, usare direttamente anziché CosmosClient basarsi su __jObject:
var cosmosClient = context.Database.GetCosmosClient();
var container = cosmosClient.GetContainer("myDatabase", "myContainer");
var response = await container.ReadItemAsync<JsonElement>("1", new PartitionKey("1"));
var billingAddress = response.Resource.GetProperty("BillingAddress").GetString();
Per altre informazioni, vedere Uso di dati non strutturati in Azure Cosmos DB.
Il livello di compatibilità di SQL Server è ora impostato per impostazione predefinita su 160
Problema di tracciamento n. 38198
Comportamento precedente
In precedenza, quando si usa UseSqlServer senza configurare in modo esplicito un livello di compatibilità SQL Server, EF Core ha impostato il livello di compatibilità 150, corrispondente a SQL Server 2019.
Nuovo comportamento
A partire da EF Core 11.0, UseSqlServer usa per impostazione predefinita il livello di compatibilità 160, che corrisponde a SQL Server 2022. In questo modo EF può generare SQL che usa le funzionalità di SQL Server 2022 per impostazione predefinita. Ad esempio, alcune query ora usano LEAST e GREATEST, incluse le traduzioni per Math.Min, Math.Max, Least, Greatest e alcuni pattern Take/Skip.
Se il database viene eseguito in SQL Server 2019 o versione precedente o è configurato con un livello di compatibilità inferiore a 160, alcuni sql generati da EF Core potrebbero non essere più supportati dal database.
Perché
SQL Server 2022 è disponibile da diversi anni e l'uso del livello di compatibilità 160 per impostazione predefinita consente a EF Core di generare SQL più semplice ed efficiente per le versioni più recenti di SQL Server.
Mitigazioni
Se il database non supporta il livello di compatibilità 160, configurare EF Core per l'uso del livello di compatibilità supportato dal database:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("<connection string>", o => o.UseCompatibilityLevel(150));
}
Per altre informazioni, vedere la documentazione sul livello di compatibilità di SQL Server.
EF Core ora genera un'eccezione per impostazione predefinita quando non vengono trovate migrazioni
Problema di rilevamento n. 35218
Comportamento precedente
In precedenza, quando si chiama Migrate o MigrateAsync su un database senza migrazioni nell'assembly, EF Core ha registrato un messaggio informativo e restituito senza applicare alcuna modifica.
Nuovo comportamento
A partire da EF Core 11.0, EF Core genera un'eccezione per impostazione predefinita quando non viene trovata alcuna migrazione nell'assembly. Questo comportamento è coerente con il PendingModelChangesWarning comportamento introdotto in EF 9.0.
Perché
La chiamata Migrate() o MigrateAsync() quando non esistono migrazioni indica in genere una configurazione errata. Anziché continuare in modo invisibile all'utente e lasciare il database in uno stato potenzialmente errato, EF Core avvisa ora gli sviluppatori di questo problema immediatamente.
Mitigazioni
Se si chiama Migrate() intenzionalmente senza eseguire migrazioni, ad esempio perché lo schema del database viene gestito tramite altri mezzi, rimuovere la Migrate() chiamata o eliminare l'eccezione configurando avvisi:
options.ConfigureWarnings(w => w.Ignore(RelationalEventId.MigrationsNotFound))
Oppure per registrare l'evento invece di generare:
options.ConfigureWarnings(w => w.Log(RelationalEventId.MigrationsNotFound))
EFOptimizeContext La proprietà MSBuild è stata rimossa
Problema di rilevamento n. 35079
Comportamento precedente
In precedenza, la proprietà MSBuild potrebbe essere impostata su EFOptimizeContext per abilitare la true generazione di codice di query compilata e precompilata durante la compilazione o la pubblicazione:
<EFOptimizeContext Condition="'$(Configuration)'=='Release'">true</EFOptimizeContext>
Nuovo comportamento
A partire da EF Core 11.0, la EFOptimizeContext proprietà MSBuild è stata rimossa. La generazione del codice è ora controllata esclusivamente tramite le EFScaffoldModelStage proprietà e EFPrecompileQueriesStage . Quando PublishAOT è impostato su true, la generazione del codice viene abilitata automaticamente durante la pubblicazione senza che sia necessaria alcuna proprietà aggiuntiva.
Perché
Le EFScaffoldModelStage proprietà e EFPrecompileQueriesStage forniscono già un controllo granulare su quando si verifica la generazione del codice.
EFOptimizeContext era una porta di abilitazione ridondante.
Mitigazioni
Sostituire gli utilizzi di EFOptimizeContext con le proprietà EFScaffoldModelStage e EFPrecompileQueriesStage. Questi valori possono essere impostati su publish o build per controllare in quale fase si verifica la generazione del codice:
<EFScaffoldModelStage>publish</EFScaffoldModelStage>
<EFPrecompileQueriesStage>publish</EFPrecompileQueriesStage>
Qualsiasi altro valore ,ad esempio , nonedisabilita la generazione corrispondente.
Se è stato PublishAOT impostato su true, la generazione del codice viene abilitata automaticamente durante la pubblicazione e non è necessaria alcuna configurazione aggiuntiva.
I pacchetti degli strumenti di Entity Framework non fanno più riferimento a Microsoft.EntityFrameworkCore.Design
Problema di rilevamento n. 37739
Comportamento precedente
In precedenza, i pacchetti NuGet Microsoft.EntityFrameworkCore.Tools e Microsoft.EntityFrameworkCore.Tasks avevano una dipendenza da Microsoft.EntityFrameworkCore.Design.
Nuovo comportamento
A partire da EF Core 11.0, i pacchetti NuGet Microsoft.EntityFrameworkCore.Tools e Microsoft.EntityFrameworkCore.Tasks non hanno più una dipendenza da Microsoft.EntityFrameworkCore.Design.
Perché
Non esiste alcuna dipendenza rigida dal codice in Microsoft.EntityFrameworkCore.Design e questa dipendenza causava problemi durante l'uso dell'ultima Microsoft.EntityFrameworkCore.Tools con progetti destinati a framework meno recenti.
Mitigazioni
Se il tuo progetto si basa su Microsoft.EntityFrameworkCore.Design portato in modo transitivo attraverso i pacchetti degli strumenti, aggiungi un riferimento diretto ad esso nel tuo progetto:
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="11.0.0" PrivateAssets="all" />
Le proprietà SqlVector non vengono più caricate per impostazione predefinita
Problema di rilevamento n. 37279
Comportamento precedente
In precedenza, durante l'esecuzione di query sulle entità con le proprietà SqlVector<T>, EF Core includeva la colonna vettoriale nelle dichiarazioni SELECT e popolava la proprietà nell'entità restituita.
Nuovo comportamento
A partire da EF Core 11.0, le proprietà SqlVector<T> non sono più incluse nelle istruzioni SELECT al momento della materializzazione delle entità. La proprietà sarà null sulle entità restituite.
Le proprietà vettoriali possono comunque essere usate nelle clausole WHERE e ORDER BY — incluse con VectorDistance() e VectorSearch() — ma non saranno incluse nella proiezione delle entità.
Perché
Le colonne vettoriali possono essere molto grandi, contenenti centinaia o migliaia di valori a virgola mobile. Nella maggior parte dei casi, i vettori vengono scritti nel database e quindi usati per la ricerca, senza dover essere letti di nuovo. Escluderli da SELECT per impostazione predefinita evita il trasferimento inutile di dati.
Mitigazioni
Annotazioni
Un meccanismo per la reintegrazione delle proprietà vettoriali nel caricamento automatico verrà introdotto in una fase successiva della versione EF Core 11.
Se è necessario leggere i valori del vettore indietro, usare una proiezione esplicita:
var embeddings = await context.Blogs
.Select(b => new { b.Id, b.Embedding })
.ToListAsync();
Cosmos: le raccolte di proprietà vuote restituiscono ora una raccolta vuota anziché null
Problema di rilevamento n. 36577
Comportamento precedente
In precedenza, durante l'esecuzione di query sulle entità tramite il provider Azure Cosmos DB, in cui una raccolta posseduta non conteneva elementi, la proprietà della raccolta era null sull'entità materializzata.
Nuovo comportamento
A partire da EF Core 11.0, il provider Azure Cosmos DB inizializza correttamente le raccolte di proprietà vuote, restituendo una raccolta vuota anziché null.
Perché
Il comportamento precedente di materializzare le collezioni possedute vuote come null era un bug.
Mitigazioni
Se il codice controlla esplicitamente le proprietà delle raccolte possedute per null verificare che la raccolta sia vuota, questi controlli possono essere semplicemente rimossi, poiché la raccolta è ora sempre inizializzata.
// Before
if (entity.OwnedCollection is null or { Count: 0 })
{
// treated as empty
}
// After
if (entity.OwnedCollection is { Count: 0 })
{
// treated as empty
}
Cosmos: la proprietà discriminatoria predefinita è ora denominata Discriminator nel modello
Comportamento precedente
EF aggiunge automaticamente una proprietà discriminatoria per identificare il tipo di entità rappresentato da un documento JSON. Il nome di questa proprietà nel documento JSON è stato modificato da Discriminator a $type in EF Core 9.0. A tale scopo, Entity Framework viene usato $type come nome della proprietà discriminatoria sia nel modello di Entity Framework che nel documento JSON archiviato.
Poiché $type non è un identificatore C# valido, il nome della proprietà shadow risultante ha causato la generazione di codice non valido per i modelli compilati e le query precompilate usate con AOT nativo.
Nuovo comportamento
A partire da EF Core 11.0, la proprietà discriminatoria predefinita viene nuovamente denominata Discriminator nel modello EF, mentre il nome scritto nel documento JSON rimane invariato e rimane $type per impostazione predefinita. In altre parole, il nome della proprietà del modello e il nome della proprietà JSON sono ora disaccoppiati:
-
entityType.FindDiscriminatorProperty().NamerestituisceDiscriminator. -
entityType.FindDiscriminatorProperty().GetJsonPropertyName()restituisce$type.
Il formato dei documenti archiviati non è interessato da questa modifica, quindi i dati esistenti continuano a funzionare senza modifiche.
Perché
Ef deriva alcuni identificatori C# generati (ad esempio, nomi di variabili di proprietà shadow) dai metadati del modello, ad esempio i nomi delle proprietà. Poiché $type non è un identificatore C# valido, usarlo come nome della proprietà del modello ha prodotto codice noncompilato per i modelli compilati e le query precompilate. La denominazione della proprietà Discriminator del modello (identificatore valido) durante la scrittura $type nel documento mantiene il codice generato valido senza modificare il formato su disco.
Mitigazioni
Per la maggior parte delle applicazioni non è necessaria alcuna azione, poiché i documenti archiviati non sono interessati e continuano a usare $type.
Se il codice fa riferimento al discriminante in base al nome della proprietà del modello , $type ad esempio tramite Property in una query o un filtro di query o cercando la proprietà nei metadati, aggiornarla in modo da usarla Discriminator :
// Before
var query = context.Set<Session>().Where(e => EF.Property<string>(e, "$type") == "Lecture");
// After
var query = context.Set<Session>().Where(e => EF.Property<string>(e, "Discriminator") == "Lecture");
Per modificare il nome della proprietà discriminante JSON per l'intero modello in un'unica posizione, ad esempio per allinearlo al nome della proprietà del modello, usare l'API a livello HasEmbeddedDiscriminatorName di modello anziché configurare ogni tipo di entità singolarmente:
modelBuilder.HasEmbeddedDiscriminatorName("Discriminator");
Per modificare solo il nome JSON per un tipo di entità specifico, ad esempio per allinearlo al nome della proprietà del modello, configurare il nome JSON della proprietà discriminatoria con ToJsonProperty:
modelBuilder.Entity<Session>().Property<string>("Discriminator").ToJsonProperty("Discriminator");
Per ripristinare il comportamento precedente in cui la proprietà discriminatoria è denominata $type anche nel modello, configurarne il nome in modo esplicito con HasDiscriminator. Si noti che questa reintroduzione di un identificatore C# non valido e non è consigliabile quando si usano modelli compilati o query precompilate:
modelBuilder.Entity<Session>().HasDiscriminator<string>("$type");
Cosmos: i valori a virgola mobile vengono ora troncati durante la materializzazione dei tipi a virgola fissa
Problema di rilevamento n. 38138
Comportamento precedente
In precedenza, quando una proiezione di query restituisce un valore a virgola mobile (ad esempio, il risultato di un'espressione numerica, ad 3 / 4 esempio restituita da Cosmos come 0.75) e la proprietà di destinazione era un tipo a virgola fissa (int, long, decimale così via), EF Core arrotonderebbe il valore. Ad esempio, 0.75 materializzare come 1.
Nuovo comportamento
A partire da EF Core 11, tali valori vengono troncati anziché arrotondati.
0.75ora si materializza come 0, corrispondente .NET comportamento di troncamento intero ((int)0.75 == 0).
Perché
Il troncamento è il comportamento .NET standard per le conversioni numeriche esplicite ed è coerente con il comportamento di altri provider. Il comportamento di arrotondamento precedente era un bug.
Mitigazioni
Se si è basato sul comportamento di arrotondamento precedente, applicare l'arrotondamento esplicito nelle query usando Math.Round:
var result = await context.Products
.Select(p => (int)Math.Round((double)p.Int / (p.Int + 1)))
.SingleAsync();
Le raccolte JSON di proprietà senza una chiave esplicita sono obsolete
Problema di rilevamento n. 37289
Comportamento precedente
In precedenza, i tipi di entità di proprietà mappati a una colonna JSON tramite ToJson potrebbero essere usati come raccolte senza configurare una chiave primaria esplicita. EF Core sintetizza una chiave ordinale (posizionale) dietro le quinte per identificare ogni elemento nella raccolta:
public class Blog
{
public int Id { get; set; }
public List<Post> Posts { get; set; } = new();
}
public class Post
{
// No key property
public required string Title { get; set; }
public required string Content { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().OwnsMany(b => b.Posts, b => b.ToJson());
Nuovo comportamento
A partire da EF Core 11.0, la configurazione di una raccolta JSON di proprietà senza una chiave esplicita genera un OwnedEntityMappedToJsonCollectionWarning avviso. Il mapping continua a funzionare, ma è ora considerato deprecato e dovrebbe essere rimosso in una versione futura.
Le entità JSON di proprietà con una chiave primaria esplicita, nonché i riferimenti JSON non di proprietà della raccolta, non sono interessate da questa modifica.
Perché
I tipi complessi sono diventati completamente supportati in EF Core 10, incluso per il mapping JSON. I tipi complessi sono più adatti dei tipi posseduti per i documenti JSON: hanno semantica di valore e nessuna identità, il che evita molti dei problemi derivanti dall'uso di tipi di entità posseduti, che sono a tutti gli effetti tipi di entità, per modellare ciò che è fondamentalmente un valore incorporato in un altro documento. In particolare, le raccolte JSON di proprietà senza una chiave esplicita si basavano su una chiave ordinale sintetica, che presenta limitazioni note e casi di angolo.
Mitigazioni
La mitigazione consigliata consiste nel eseguire la migrazione del tipo a un tipo complesso, che è ora il modo preferito per eseguire il mapping dei tipi a JSON:
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().ComplexCollection(b => b.Posts, b => b.ToJson());
In alternativa, se devi mantenere il mapping del tipo owned, configura una chiave primaria non shadow sul tipo owned. Dopo aver configurato una chiave, l'avviso non si applica più:
public class Post
{
public int Id { get; set; }
public required string Title { get; set; }
public required string Content { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().OwnsMany(b => b.Posts, b =>
{
b.ToJson();
b.HasKey(p => p.Id);
});
Se non è possibile eseguire immediatamente la migrazione, è possibile eliminare l'avviso tramite ConfigureWarnings:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.ConfigureWarnings(w => w.Ignore(CoreEventId.OwnedEntityMappedToJsonCollectionWarning));
Property non configura più raccolte primitive
Comportamento precedente
In precedenza, la chiamata per un membro il cui tipo CLR è una raccolta (ad esempio List<int>) potrebbe comportare Property la configurazione del membro come raccolta primitiva, perché una proprietà potrebbe essere promossa a una raccolta primitiva in fase di finalizzazione del modello in base al relativo tipo.
Nuovo comportamento
A partire da EF Core 11.0, se una proprietà è una raccolta primitiva viene determinata interamente quando la proprietà è configurata. Una raccolta primitiva deve essere configurata con PrimitiveCollection (o individuata come una per convenzione). Property ora configura sempre il membro come proprietà non di raccolta (scalare) e non esiste più alcuna promozione in fase di finalizzazione in una raccolta primitiva.
Perché
Il trattamento del tipo di elemento come preoccupazione per il tempo di finalizzazione ha portato a incoerenze e bug. Ad esempio, una proprietà può essere individuata come raccolta primitiva, ma successivamente si risolve in un convertitore di valori ereditati, lasciando un tipo di elemento non aggiornato che ha causato la finalizzazione di un InvalidCastException modello. Rendendo le raccolte primitive un problema in fase di creazione rende anche il mapping non ambiguo in casi come byte[], dove in caso contrario non è chiaro se il membro deve essere mappato come scalare binario o come raccolta di byte.
Mitigazioni
Se si è fatto affidamento su Property per configurare una raccolta primitiva, passare invece a PrimitiveCollection :
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().PrimitiveCollection(b => b.Tags);
Nella maggior parte dei casi non è necessaria alcuna modifica, poiché le raccolte primitive vengono individuate per convenzione.
Le query suddivise generano ora quando vengono rilevate modifiche simultanee
Problema di rilevamento n. 33826
Comportamento precedente
In precedenza, quando una query divisa (usando AsSplitQuery()) ha rilevato righe figlio non ordinate o orfane causate da modifiche simultanee dei dati tra le istruzioni SQL della query divisa, EF Core ha eliminato automaticamente le raccolte figlio interessate. Il risultato è un'entità con una raccolta vuota anche se le righe correlate sono ancora presenti. Non è stata generata alcuna eccezione e non è stato registrato alcun avviso.
Nuovo comportamento
A partire da EF Core 11.0, EF Core genera un'eccezione DbQueryConcurrencyException quando non è possibile correlare i risultati delle query suddivise a causa di modifiche simultanee ai dati. Il messaggio di eccezione descrive la situazione e suggerisce la correzione:
Impossibile correlare i risultati di una query divisa perché i dati sono stati modificati simultaneamente durante l'esecuzione della query. Eseguire di nuovo la query o eseguirla all'interno di una transazione serializzabile o snapshot per impedire modifiche simultanee.
Perché
La restituzione invisibile all'utente di dati non corretti (raccolte vuote per entità con righe correlate) è molto peggiore rispetto alla visualizzazione di un errore. Questo scenario è intrinsecamente causato dalla mancanza di garanzie di coerenza dei dati nelle query suddivise quando il database viene modificato tra istruzioni. La generazione di un'eccezione ritentabile rende visibile il problema e fornisce ai chiamanti un percorso chiaro per il ripristino.
Mitigazioni
La mitigazione più semplice consiste nell'eseguire nuovamente la query; la modifica simultanea è temporanea e in genere il nuovo tentativo avrà esito positivo:
const int maxRetries = 3;
List<Blog> blogs;
for (var attempt = 0; attempt < maxRetries; attempt++)
{
try
{
blogs = await context.Blogs
.Include(b => b.Posts)
.AsSplitQuery()
.ToListAsync();
break;
}
catch (DbQueryConcurrencyException) when (attempt < maxRetries - 1)
{
// Retry on concurrent modification
}
}
In alternativa, eseguire il wrapping della query divisa in una transazione serializzabile o snapshot per impedire che le modifiche simultanee influiscano sui risultati:
await using var transaction =
await context.Database.BeginTransactionAsync(IsolationLevel.Serializable);
var blogs = await context.Blogs
.Include(b => b.Posts)
.AsSplitQuery()
.ToListAsync();
await transaction.CommitAsync();
Se non è accettabile né riprovare né una transazione, passare a una singola query (AsSingleQuery()) che è sempre coerente:
var blogs = await context.Blogs
.Include(b => b.Posts)
.AsSingleQuery()
.ToListAsync();
Microsoft. Modifiche che causano un'interruzione di Data.Sqlite
Annotazioni
SQLitePCLRaw è una libreria esterna gestita dalla community non di proprietà o gestita da Microsoft. Microsoft. Data.Sqlite dipende da esso per la connettività SQLite.
Riassunto
| cambiamento critico | Impact |
|---|---|
| Microsoft. Data.Sqlite non supporta più .NET Framework | Intermedio |
| Alcuni pacchetti bundle SQLitePCLRaw non vengono più mantenuti | Intermedio |
| SQLite non supporta più la piattaforma UWP e i Xamarin classici | Low |
Modifiche a impatto medio
Microsoft. Data.Sqlite non supporta più .NET Framework
Problema di rilevamento n. 35599
Comportamento precedente
In precedenza, Microsoft.Data.Sqlite e Microsoft.Data.Sqlite.Core di destinazione netstandard2.0, che consentivano l'uso da applicazioni .NET Framework.
Nuovo comportamento
Microsoft.Data.Sqlite A partire dalla versione 11.0, entrambi i pacchetti sono destinati net10.0 solo a . .NET Applicazioni Framework non possono più fare riferimento o usare Microsoft.Data.Sqlite la versione 11.0.
Perché
La netstandard2.0 destinazione resa meno recente, le destinazioni .NET non supportate sembrano essere supportate e mascherano anche le differenze dell'API, DateOnly ad esempio e TimeOnly il supporto. La destinazione della versione minima supportata .NET rende esplicitamente chiara la superficie della piattaforma supportata.
Mitigazioni
Se possibile, spostare l'applicazione in .NET 10 o versione successiva.
Se è necessario rimanere in .NET Framework, rimanere nella versione di manutenzione 10.0.x più recenteMicrosoft.Data.Sqlite. La riga 10.0.x usa SQLitePCLRaw.bundle_e_sqlite3, consentendo alle applicazioni di .NET Framework di aggiornare la versione di riferimento anche dopo Microsoft.Data.Sqlite aver interrotto SQLitePCLRaw.bundle_e_sqlite3 la ricezione degli aggiornamenti.
Alcuni pacchetti bundle SQLitePCLRaw non vengono più mantenuti
Problema di rilevamento n. 5108
Comportamento precedente
In precedenza, i SQLitePCLRaw.bundle_e_sqlcipherpacchetti , SQLitePCLRaw.bundle_sqlite3SQLitePCLRaw.bundle_winsqlite3, SQLitePCLRaw.bundle_green, e SQLitePCLRaw.bundle_e_sqlite3mc forniscono un modo pratico per configurare SQLitePCLRaw con il provider SQLite corrispondente.
Nuovo comportamento
I SQLitePCLRaw.bundle_e_sqlcipherpacchetti , SQLitePCLRaw.bundle_sqlite3, SQLitePCLRaw.bundle_greenSQLitePCLRaw.bundle_winsqlite3, e SQLitePCLRaw.bundle_e_sqlite3mc non vengono più aggiornati dal manutentore SQLitePCLRaw. Non sono compatibili con SQLitePCLRaw.Core la versione 3.0 e versioni successive, quindi le applicazioni che fanno riferimento direttamente a uno di questi pacchetti insieme SQLitePCLRaw.Core a 3.x riscontreranno conflitti. Le applicazioni devono eseguire la migrazione alle alternative consigliate per evitare interruzioni future.
Perché
Il manutentore SQLitePCLRaw ha rimosso questi bundle nella versione 3.0; ogni bundle contiene solo una singola riga di codice di configurazione e aggiunge un sovraccarico di creazione pacchetti non necessario, mentre i pacchetti del provider sottostante continuano a essere supportati. Il SQLitePCLRaw.bundle_e_sqlcipher pacchetto è particolarmente interessato: ha fornito build abilitate per la crittografia che vengono mantenute a malapena, che è un problema di sicurezza per il software di crittografia in cui le vulnerabilità potrebbero non essere crittografate.
Mitigazioni
Se si usa SQLitePCLRaw.bundle_e_sqlcipher (SQLite abilitato per la crittografia), eseguire la migrazione a una delle alternative seguenti:
SQLite3 Multiple Cifrature: i pacchetti NuGet sono disponibili da SQLite3MultipleCiphers-NuGet. Fare riferimento
Microsoft.Data.Sqlite.Coreinsieme aSQLite3MC.PCLRaw.bundle:<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="11.0.0" /> <PackageReference Include="SQLite3MC.PCLRaw.bundle" Version="2.x.x" />Quando si crittografa un nuovo database o si apre un database esistente crittografato con SQLCipher, configurare lo schema di crittografia usando parametri URI, ad esempio :
Data Source=file:example.db?cipher=sqlcipher&legacy=4. Per informazioni dettagliate, vedere Come aprire un database esistente crittografato con SQLCipher .SQLite Encryption Extension (SEE): implementazione ufficiale della crittografia del team SQLite. È necessaria una licenza a pagamento. Vedere https://sqlite.org/com/see.html e il servizio di compilazione SQLite di SourceGear per le opzioni NuGet.
SQLCipher: acquistare build supportate da Zetetic oppure compilare il codice open source manualmente.
Se si usa SQLitePCLRaw.bundle_sqlite3 o SQLitePCLRaw.bundle_winsqlite3, sostituire il pacchetto bundle con il pacchetto del provider corrispondente:
<!-- Old -->
<PackageReference Include="SQLitePCLRaw.bundle_sqlite3" Version="2.x.x" />
<!-- or -->
<PackageReference Include="SQLitePCLRaw.bundle_winsqlite3" Version="2.x.x" />
<!-- New -->
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="3.x.x" />
<!-- or -->
<PackageReference Include="SQLitePCLRaw.provider.winsqlite3" Version="3.x.x" />
Aggiungere quindi l'inizializzazione esplicita prima di usare SQLite:
// For sqlite3
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
}
// For winsqlite3
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_winsqlite3());
}
Se si usa SQLitePCLRaw.bundle_e_sqlite3mc, sostituire il riferimento al pacchetto con SQLite3MC.PCLRaw.bundle:
<!-- Old -->
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3mc" Version="2.x.x" />
<!-- New -->
<PackageReference Include="SQLite3MC.PCLRaw.bundle" Version="2.x.x" />
Se si usa SQLitePCLRaw.bundle_green, passare a SQLitePCLRaw.bundle_e_sqlite3. In alternativa, usare SQLitePCLRaw.config.e_sqlite3 abbinato a un pacchetto di libreria nativa separato, SourceGear.sqlite3ad esempio , che consente di aggiornare la versione DI SQLite in modo indipendente:
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.x.x" />
Se si usa solo iOS e si vuole usare la libreria SQLite di sistema, fare riferimento direttamente al provider e inizializzarlo in modo esplicito:
<PackageReference Include="SQLitePCLRaw.Core" Version="3.x.x" />
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="3.x.x" />
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
}
Per altre informazioni, vedere Le opzioni di crittografia SQLite per l'uso con SQLitePCLRaw e SQLitePCLRaw 3.0 Note sulla versione.
Modifiche a basso impatto
SQLite non supporta più la piattaforma UWP e i Xamarin classici
Problema di rilevamento n. 5108
Comportamento precedente
In precedenza, SQLitePCLRaw.bundle_e_sqlite3 includevano build SQLite native per Piattaforma UWP (Universal Windows Platform) e Xamarin classiche (Xamarin.iOS, Xamarin. Android e Xamarin. Destinazioni Mac).
Nuovo comportamento
SQLitePCLRaw.bundle_e_sqlite3 A partire dalla versione 2.1.12 (a cui si fa riferimento per Microsoft.Data.Sqlite la versione 11.0), le build native per UWP e le Xamarin classiche non sono più incluse. Le applicazioni destinate a queste piattaforme non possono più usare la libreria SQLite nativa in bundle.
Perché
SQLite 3.53.0 (fornito dalla SQLitePCLRaw.bundle_e_sqlite3 versione 2.1.12) non supporta più la piattaforma UWP e i Xamarin classici. Il manutentore SQLitePCLRaw ha eliminato queste build per mantenere il passo con le versioni più recenti di SQLite upstream.
Mitigazioni
Eseguire la migrazione di applicazioni UWP alle applicazioni SDK per app di Windows e Xamarin classiche a .NET MAUI, supportate nei .NET moderni.
Se devi rimanere in UWP o Xamarin classica, rimani su una versione precedente di SQLitePCLRaw.bundle_e_sqlite3 che include ancora le build native per queste piattaforme.