Modifiche di rilievo in EF Core 11 (EF11)

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:

Riassunto

Annotazioni

Se si usa Microsoft.Data.Sqlite, vedere la sezione distinta riportata di seguito relativa alle modifiche dirompenti in Microsoft.Data.Sqlite.

cambiamento critico Impact
Cosmos: le proprietà non mappate non vengono più mantenute Alto
Sync I/O tramite il provider di Azure Cosmos DB è stato completamente rimosso Intermedio
Microsoft. Data.SqlClient è stato aggiornato alla versione 7.0 Intermedio
Cosmos: eccezione generata quando una proiezione restituisce un valore non definito Intermedio
Cosmos: i caratteri non validi id non sono più preceduti da escape Intermedio
Cosmos: __jObject proprietà shadow rimossa; JObject non più usato per la serializzazione Low
Il livello di compatibilità di SQL Server è ora impostato per impostazione predefinita su 160 Low
EF Core ora genera un'eccezione per impostazione predefinita quando non vengono trovate migrazioni Low
EFOptimizeContext La proprietà MSBuild è stata rimossa Low
i pacchetti degli strumenti EF non fanno più riferimento a Microsoft.EntityFrameworkCore.Design Low
Le proprietà SqlVector non vengono più caricate per impostazione predefinita Low
Cosmos: le raccolte di proprietà vuote restituiscono ora una raccolta vuota anziché null Low
Cosmos: la proprietà discriminatoria predefinita è ora denominata Discriminator nel modello Low
Cosmos: i valori a virgola mobile vengono ora troncati durante la materializzazione dei tipi a virgola fissa Low
Le raccolte JSON di proprietà senza una chiave esplicita sono obsolete Low
Property non configura più raccolte primitive Low
Le query suddivise generano ora quando vengono rilevate modifiche simultanee Low

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 CosmosClient direttamente 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 id valori usando le sequenze di escape precedenti ( ad esempio Post|1|^2F). Dopo l'aggiornamento a EF Core 11, EF genererà valori senza caratteri di escape id (ad esempio Post|1|/) e non troverà più i documenti esistenti. Per continuare ad accedere ai dati esistenti senza migrazione, torna al comportamento precedente usando l'opzione AppContext descritta 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 id di 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 era undefined. 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 InvalidOperationException con 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

Richiesta pull n. 38458

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().Name restituisce Discriminator.
  • 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.Core insieme a SQLite3MC.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.