Změny způsobující chybu v EF Core 6.0

Následující změny rozhraní API a chování mají potenciál přerušit stávající aplikace, které se aktualizují na EF Core 6.0.

Cílová architektura

EF Core 6.0 cílí na .NET 6. Aplikace, které cílí na starší verze .NET, .NET Core a .NET Framework, budou muset cílit na .NET 6, aby používaly EF Core 6.0.

Shrnutí

Změna způsobující chybu Dopad
Vnořené volitelné závislé osoby sdílející tabulku a bez požadovaných vlastností nelze uložit. Vysoká
Změna vlastníka vlastněné entity teď vyvolá výjimku. Střední
Azure Cosmos DB: Související typy entit se zjistí jako vlastněné Střední
SQLite: Připojení iony jsou ve fondu Střední
Relace M:N bez namapovaných entit spojení se teď vygenerují. Střední
Vyčištění mapování mezi hodnotami DeleteBehavior a ON DELETE Nízká
Databáze v paměti ověřuje, že požadované vlastnosti neobsahují hodnoty null. Nízká
Odebrání poslední OBJEDNÁVKY BY při připojování ke kolekcím Nízká
DbSet už neimplementuje IAsyncEnumerable Nízká
Návratový typ entity TVF se ve výchozím nastavení mapuje také na tabulku. Nízká
Kontrola jedinečnosti názvu omezení je teď ověřená. Nízká
Přidání rozhraní metadat IReadOnly a odebraných rozšiřujících metod Nízká
IExecutionStrategy je nyní singletonová služba Nízká
SQL Server: Další chyby se považují za přechodné Nízká
Azure Cosmos DB: V hodnotách ID se uchytávají další znaky. Nízká
Některé služby Singleton jsou nyní vymezeny. Nízké*
Nové rozhraní API pro ukládání do mezipaměti pro rozšíření, která přidávají nebo nahrazují služby Nízké*
Nová procedura inicializace modelu snímků a návrhu Nízká
OwnedNavigationBuilder.HasIndex vrátí jiný typ. Nízká
DbFunctionBuilder.HasSchema(null) Přepisuje [DbFunction(Schema = "schema")] Nízká
Předem inicializované navigace se přepisují hodnotami z databázových dotazů. Nízká
Neznámé hodnoty řetězců výčtu v databázi se při dotazování nepřevedou na výchozí výčt. Nízká
DbFunctionBuilder.HasTranslation nyní poskytuje argumenty funkce jako IReadOnlyList místo IReadOnlyCollection. Nízká
Výchozí mapování tabulek se neodebere, když je entita namapovaná na funkci s hodnotou tabulky. Nízká
dotnet-ef targets .NET 6 Nízká
IModelCacheKeyFactory implementace může být potřeba aktualizovat, aby bylo možné zpracovat ukládání do mezipaměti v době návrhu. Nízká
NavigationBaseIncludeIgnored je teď ve výchozím nastavení chyba. Nízká

* Tyto změny jsou zvláště zajímavé pro autory poskytovatelů databází a rozšíření.

Změny s vysokým dopadem

Vnořené volitelné závislé osoby sdílející tabulku a bez požadovaných vlastností nejsou zakázány.

Problém se sledováním č. 24558

Staré chování

Modely s vnořenými volitelnými závislými závislostmi sdílející tabulku a bez požadovaných vlastností byly povoleny, ale mohly by způsobit ztrátu dat při dotazování na data a následné opětovné uložení. Představte si například následující model:

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ContactInfo ContactInfo { get; set; }
}

[Owned]
public class ContactInfo
{
    public string Phone { get; set; }
    public Address Address { get; set; }
}

[Owned]
public class Address
{
    public string House { get; set; }
    public string Street { get; set; }
    public string City { get; set; }
    public string Postcode { get; set; }
}

Žádné vlastnosti nejsou ContactInfoAddress povinné a všechny tyto typy entit se mapují na stejnou tabulku. Pravidla pro volitelné závislé osoby (na rozdíl od povinných závislých) říkají, že pokud jsou všechny sloupce pro ContactInfo hodnotu null, nebude při dotazování na vlastníka Customervytvořena žádná instance ContactInfo . To však také znamená, že se nevytvořila žádná instance Address , a to ani v případě Address , že sloupce nejsou null.

Nové chování

Při pokusu o použití tohoto modelu se teď zobrazí následující výjimka:

System.InvalidOperationException: Typ entity ContactInfo je volitelný závislý pomocí sdílení tabulky a obsahuje další závislé objekty bez jakékoli požadované nesdílené vlastnosti k identifikaci, zda entita existuje. Pokud všechny vlastnosti s možnou hodnotou null obsahují hodnotu null v databázi, instance objektu nebude vytvořena v dotazu, což způsobí ztrátu vnořených závislých hodnot. Přidejte požadovanou vlastnost pro vytváření instancí s hodnotami null pro jiné vlastnosti nebo označte příchozí navigaci jako požadovanou pro vždy vytvoření instance.

Tím zabráníte ztrátě dat při dotazování a ukládání dat.

Proč

Použití modelů s vnořenými volitelnými závislými objekty sdílející tabulku a bez požadovaných vlastností často vedlo ke ztrátě tichých dat.

Omezení rizik

Nepoužívejte volitelné závislé osoby, které sdílejí tabulku a neobsahují žádné požadované vlastnosti. Existují tři jednoduché způsoby, jak to udělat:

  1. Vyžadovat závislé osoby. To znamená, že závislá entita bude mít po dotazech vždy hodnotu, i když všechny její vlastnosti mají hodnotu null. Příklad:

    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
    
        [Required]
        public Address Address { get; set; }
    }
    

    Nebo:

    modelBuilder.Entity<Customer>(
        b =>
            {
                b.OwnsOne(e => e.Address);
                b.Navigation(e => e.Address).IsRequired();
            });
    
  2. Ujistěte se, že závislý obsahuje aspoň jednu požadovanou vlastnost.

  3. Namapujte volitelné závislé objekty na vlastní tabulku místo sdílení tabulky s objektem zabezpečení. Příklad:

    modelBuilder.Entity<Customer>(
        b =>
            {
                b.ToTable("Customers");
                b.OwnsOne(e => e.Address, b => b.ToTable("CustomerAddresses"));
            });
    

Problémy s volitelnými závislostmi a příklady těchto omezení rizik jsou součástí dokumentace k tomu, co je nového v EF Core 6.0.

Změny se středním dopadem

Změna vlastníka vlastněné entity teď vyvolá výjimku.

Problém se sledováním č. 4073

Staré chování

Bylo možné znovu přiřadit vlastní entitu jiné entitě vlastníka.

Nové chování

Tato akce teď vyvolá výjimku:

Vlastnost {entityType}. {property} je součástí klíče, takže ho nelze upravit ani označit jako změněný. Pokud chcete změnit objekt zabezpečení existující entity s identifikací cizího klíče, nejprve odstraňte závislý objekt a vyvolejte saveChanges a pak přidružte závislost k novému objektu zabezpečení.

Proč

I když nevyžadujeme, aby vlastnosti klíče existovaly ve vlastním typu, EF stále vytvoří stínové vlastnosti, které se použijí jako primární klíč a cizí klíč odkazující na vlastníka. Když se entita vlastníka změní, způsobí změnu hodnot cizího klíče ve vlastněné entitě a protože se také používají jako primární klíč, výsledkem je změna identity entity. V EF Core se to zatím plně nepodporuje a pro vlastněné entity byly podmíněně povoleny pouze entity, což někdy vede k nekonzistentnímu internímu stavu.

Omezení rizik

Místo přiřazení stejné instance vlastníkovi novému vlastníkovi můžete přiřadit kopii a odstranit starou instanci.

Sledování problému č. 24803Co je nového: Výchozí nastavení implicitního vlastnictví

Staré chování

Stejně jako u jiných poskytovatelů byly související typy entit zjištěny jako normální (nevlastní) typy.

Nové chování

Související typy entit teď vlastní typ entity, na kterém byly zjištěny. Jako nevlastní budou zjištěny pouze typy entit, které odpovídají DbSet<TEntity> vlastnosti.

Proč

Toto chování se řídí běžným vzorem modelování dat ve službě Azure Cosmos DB při vkládání souvisejících dat do jednoho dokumentu. Azure Cosmos DB nativně nepodporuje spojování různých dokumentů, takže modelování souvisejících entit jako nesvlastně má omezenou užitečnost.

Omezení rizik

Konfigurace typu entity tak, aby byl nevlastní volání modelBuilder.Entity<MyEntity>();

SQLite: Připojení iony jsou ve fondu

Sledování problému č. 13837Co je nového: Výchozí nastavení implicitního vlastnictví

Staré chování

Dříve nebyla připojení v Microsoft.Data.Sqlite ve fondu.

Nové chování

Od verze 6.0 jsou teď připojení ve výchozím nastavení ve fondu. Výsledkem je, že se soubory databáze udržují otevřené procesem i po zavření objektu připojení ADO.NET.

Proč

Sdružování základních připojení výrazně zlepšuje výkon otevírání a zavírání objektů připojení ADO.NET. To je obzvláště patrné pro scénáře, kdy otevření základního připojení je nákladné, jako v případě šifrování, nebo ve scénářích, kde existuje velké množství krátkodobého připojení k databázi.

Omezení rizik

Připojení sdružování je možné zakázat přidáním Pooling=False do připojovací řetězec.

Některé scénáře (například odstranění souboru databáze) teď můžou nastat chyby s oznámením, že se soubor stále používá. Před provedením operací se souborem SqliteConnection.ClearPool()můžete ručně vymazat fond připojení .

SqliteConnection.ClearPool(connection);
File.Delete(databaseFile);

Relace M:N bez namapovaných entit spojení se teď vygenerují.

Problém se sledováním č. 22475

Staré chování

Generování uživatelského rozhraní (zpětné analýzy) DbContext a typy entit z existující databáze vždy explicitně mapované tabulky spojení pro spojení typů entit pro relace M:N.

Nové chování

Jednoduché tabulky spojení obsahující pouze dvě vlastnosti cizího klíče do jiných tabulek se už nenamapují na explicitní typy entit, ale mapují se jako relace M:N mezi těmito dvěma spojovanými tabulkami.

Proč

Relace M:N bez explicitních typů spojení byly zavedeny v EF Core 5.0 a představují čistější a přirozenější způsob znázornění jednoduchých spojování tabulek.

Omezení rizik

Existují dvě omezení rizik. Upřednostňovaným přístupem je aktualizovat kód tak, aby přímo používal relace M:N. Je velmi vzácné, že typ entity spojení je potřeba použít přímo v případě, že obsahuje pouze dva cizí klíče pro relace M:N.

Případně je možné entitu explicitního spojení přidat zpět do modelu EF. Předpokládejme například, že relace M:N mezi Post a Tag, přidejte zpět typ spojení a navigace pomocí částečných tříd:

public partial class PostTag
{
    public int PostsId { get; set; }
    public int TagsId { get; set; }

    public virtual Post Posts { get; set; }
    public virtual Tag Tags { get; set; }
}

public partial class Post
{
    public virtual ICollection<PostTag> PostTags { get; set; }
}

public partial class Tag
{
    public virtual ICollection<PostTag> PostTags { get; set; }
}

Pak přidejte konfiguraci pro typ spojení a navigace do částečné třídy pro DbContext:

public partial class DailyContext
{
    partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>(entity =>
        {
            entity.HasMany(d => d.Tags)
                .WithMany(p => p.Posts)
                .UsingEntity<PostTag>(
                    l => l.HasOne<Tag>(e => e.Tags).WithMany(e => e.PostTags).HasForeignKey(e => e.TagsId),
                    r => r.HasOne<Post>(e => e.Posts).WithMany(e => e.PostTags).HasForeignKey(e => e.PostsId),
                    j =>
                    {
                        j.HasKey("PostsId", "TagsId");
                        j.ToTable("PostTag");
                    });
        });
    }
}

Nakonec odeberte vygenerovanou konfiguraci relace M:N z vygenerovaného kontextu. To je potřeba, protože před explicitním typem explicitního typu entity je nutné z modelu odebrat vygenerovaný typ spojení. Tento kód bude potřeba odebrat pokaždé, když se kontext vygeneruje, ale protože výše uvedený kód je v částečných třídách, bude zachován.

Všimněte si, že s touto konfigurací je možné entitu join použít explicitně, stejně jako v předchozích verzích EF Core. Relace se ale dá použít také jako relace M:N. To znamená, že aktualizace takového kódu může být dočasné řešení, zatímco zbytek kódu se aktualizuje tak, aby používal relaci jako N:N přirozeným způsobem.

Změny s nízkým dopadem

Vyčištění mapování mezi hodnotami DeleteBehavior a ON DELETE

Problém se sledováním č. 21252

Staré chování

Některá mapování mezi chováním vztahu OnDelete() a chováním cizích klíčů ON DELETE v databázi byla v migracích i generování nekonzistentní.

Nové chování

Následující tabulka znázorňuje změny migrace.

OnDelete() PŘI ODSTRANĚNÍ
NoAction ŽÁDNÁ AKCE
ClientNoAction ŽÁDNÁ AKCE
Omezit OMEZIT
Cascasde KASKÁDY
ClientCascade OMEZITŽÁDNOU AKCI
SetNull NASTAVIT HODNOTU NULL
ClientSetNull OMEZITŽÁDNOU AKCI

Změny generování uživatelského rozhraní jsou následující.

PŘI ODSTRANĚNÍ OnDelete()
ŽÁDNÁ AKCE ClientSetNull
OMEZIT Omezení ClientSetNull
KASKÁDY Cascade
NASTAVIT HODNOTU NULL SetNull

Proč

Nová mapování jsou konzistentnější. Výchozí chování databáze typu NO ACTION je nyní upřednostňované oproti přísnějšímu a méně výkonnému chování RESTRICT.

Omezení rizik

Výchozí chování OnDelete() volitelných relací je ClientSetNull. Jeho mapování se změnilo z OMEZENÍ na ŽÁDNOU AKCI. To může způsobit generování velkého množství operací při první migraci po upgradu na EF Core 6.0.

Tyto operace můžete použít nebo je z migrace odebrat ručně, protože nemají žádný funkční dopad na EF Core.

SQL Server nepodporuje funkci RESTRICT, takže tyto cizí klíče už byly vytvořeny pomocí žádné akce. Operace migrace nebudou mít na SQL Server žádný vliv a je bezpečné je odebrat.

Databáze v paměti ověřuje, že požadované vlastnosti neobsahují hodnoty null.

Problém se sledováním č. 10613

Staré chování

Databáze v paměti povolila ukládání hodnot null, i když byla vlastnost nakonfigurována podle potřeby.

Nové chování

Databáze v paměti vyvolá Microsoft.EntityFrameworkCore.DbUpdateException při SaveChanges nebo SaveChangesAsync je volána a požadovaná vlastnost je nastavena na hodnotu null.

Proč

Chování databáze v paměti teď odpovídá chování jiných databází.

Omezení rizik

Při konfiguraci zprostředkovatele v paměti je možné obnovit předchozí chování (tj. nekontrolovat hodnoty null). Příklad:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseInMemoryDatabase("MyDatabase", b => b.EnableNullChecks(false));
}

Odebrání poslední OBJEDNÁVKY BY při připojování ke kolekcím

Problém se sledováním č. 19828

Staré chování

Při provádění JOIN SQL pro kolekce (relace 1:N), EF Core se používá k přidání ORDER BY pro každý klíčový sloupec spojené tabulky. Například načtení všech blogů se souvisejícími příspěvky bylo provedeno prostřednictvím následujícího SQL:

SELECT [b].[BlogId], [b].[Name], [p].[PostId], [p].[BlogId], [p].[Title]
FROM [Blogs] AS [b]
LEFT JOIN [Post] AS [p] ON [b].[BlogId] = [p].[BlogId]
ORDER BY [b].[BlogId], [p].[PostId]

Tyto řazení jsou nezbytné pro správnou materializaci entit.

Nové chování

Poslední ORDER BY pro připojení ke kolekci se teď vynechá:

SELECT [b].[BlogId], [b].[Name], [p].[PostId], [p].[BlogId], [p].[Title]
FROM [Blogs] AS [b]
LEFT JOIN [Post] AS [p] ON [b].[BlogId] = [p].[BlogId]
ORDER BY [b].[BlogId]

Položka ORDER BY pro sloupec ID příspěvku se už negeneruje.

Proč

Každá funkce ORDER BY ukládá další práci na straně databáze a poslední řazení není nezbytné pro potřeby materializace EF Core. Data ukazují, že odebrání tohoto posledního řazení může v některých scénářích výrazně zlepšit výkon.

Omezení rizik

Pokud vaše aplikace očekává, že se připojené entity vrátí v určitém pořadí, přidejte do dotazu operátor LINQ OrderBy .

DbSet už neimplementuje IAsyncEnumerable

Problém se sledováním č. 24041

Staré chování

DbSet<TEntity>, který se používá ke spouštění dotazů na DbContext, sloužící k implementaci IAsyncEnumerable<T>.

Nové chování

DbSet<TEntity> již neimplementuje IAsyncEnumerable<T>přímo .

Proč

DbSet<TEntity> byl původně proveden k implementaci IAsyncEnumerable<T> především za účelem povolení přímého výčtu prostřednictvím konstruktoru foreach . Bohužel, když projekt odkazuje také na System.Linq.Async , aby mohl vytvořit asynchronní operátory LINQ na straně klienta, výsledkem byla nejednoznačná chyba vyvolání mezi operátory definovanými nad IQueryable<T> a těmi definovanými na straně IAsyncEnumerable<T>. Jazyk C# 9 přidal podporu rozšíření GetEnumerator pro foreach smyčky, čímž se odstranil původní hlavní důvod pro odkazování IAsyncEnumerable.

Velká většina DbSet využití bude i nadále fungovat tak, jak je, protože tvoří operátory LINQ přes DbSet, vytvoří výčet, atd. Jedinými poškozenými použitími jsou ty, které se pokusí přetypovat DbSet přímo na IAsyncEnumerable.

Omezení rizik

Pokud potřebujete odkazovat na objekt DbSet<TEntity> jako IAsyncEnumerable<T>, zavolejte DbSet<TEntity>.AsAsyncEnumerable ho explicitně přetypovat.

Návratový typ entity TVF se ve výchozím nastavení mapuje také na tabulku.

Problém se sledováním č. 23408

Staré chování

Typ entity nebyl ve výchozím nastavení namapován na tabulku, pokud je použit jako návratový typ TVF nakonfigurovaný HasDbFunction.

Nové chování

Typ entity použitý jako návratový typ TVF zachovává výchozí mapování tabulky.

Proč

Není intuitivní, že konfigurace TVF odebere výchozí mapování tabulky pro návratový typ entity.

Omezení rizik

Pokud chcete odebrat výchozí mapování tabulky, zavolejte ToTable(EntityTypeBuilder, String):

modelBuilder.Entity<MyEntity>().ToTable((string?)null));

Kontrola jedinečnosti názvu omezení je teď ověřená.

Problém se sledováním č. 25061

Staré chování

Zkontrolujte omezení se stejným názvem, která se dají deklarovat a používat ve stejné tabulce.

Nové chování

Explicitní konfigurace dvou omezení kontroly se stejným názvem ve stejné tabulce teď způsobí výjimku. Kontrola omezení vytvořených konvencí bude přiřazena jedinečnému názvu.

Proč

Většina databází neumožňuje vytvoření dvou omezení kontroly se stejným názvem ve stejné tabulce a některé vyžadují, aby byly jedinečné i napříč tabulkami. Výsledkem by byla vyvolána výjimka při použití migrace.

Omezení rizik

V některých případech se platné názvy omezení kontroly můžou v důsledku této změny lišit. Pokud chcete zadat požadovaný název explicitně, zavolejte HasName:

modelBuilder.Entity<MyEntity>().HasCheckConstraint("CK_Id", "Id > 0", c => c.HasName("CK_MyEntity_Id"));

Přidání rozhraní metadat IReadOnly a odebraných rozšiřujících metod

Problém se sledováním č. 19213

Staré chování

Existují tři sady rozhraní metadat: IModelIMutableModel a IConventionModel také rozšiřující metody.

Nové chování

Byla přidána nová sada IReadOnly rozhraní, například IReadOnlyModel. Rozšiřující metody, které byly dříve definovány pro rozhraní metadat, byly převedeny na výchozí metody rozhraní.

Proč

Výchozí metody rozhraní umožňují přepsat implementaci. Tato implementace využívá novou implementaci modelu za běhu k zajištění lepšího výkonu.

Omezení rizik

Tyto změny by neměly mít vliv na většinu kódu. Pokud byste však používali rozšiřující metody prostřednictvím syntaxe statického vyvolání, bylo by nutné ji převést na syntaxi vyvolání instance.

IExecutionStrategy je nyní singletonová služba

Problém se sledováním č. 21350

Nové chování

IExecutionStrategy je teď jednoúčelová služba. To znamená, že každý přidaný stav ve vlastních implementacích zůstane mezi spuštěními a delegát předán ExecutionStrategy pouze jednou.

Proč

Tím se sníží přidělení na dvou horkých cestách v EF.

Omezení rizik

Implementace odvozené z ExecutionStrategy by měly vymazat jakýkoli stav v OnFirstExecution().

Podmíněná logika v delegátu předaná ExecutionStrategy do vlastní implementace IExecutionStrategy.

SQL Server: Další chyby se považují za přechodné

Problém se sledováním č. 25050

Nové chování

Chyby uvedené ve výše uvedeném problému jsou nyní považovány za přechodné. Při použití výchozí strategie provádění (bez opakování) se tyto chyby teď zabalí do instance výjimky navíc.

Proč

Dál shromažďujeme zpětnou vazbu od uživatelů i týmu SQL Serveru, u kterých chyb by se měly považovat za přechodné.

Omezení rizik

Chcete-li změnit sadu chyb, které jsou považovány za přechodné, použijte vlastní strategii spouštění, která by mohla být odvozena z SqlServerRetryingExecutionStrategy - Připojení ion Resiliency – EF Core.

Azure Cosmos DB: V hodnotách ID se uchytávají další znaky.

Problém se sledováním č. 25100

Staré chování

V EF Core 5 byl uchácený pouze '|' v id hodnotách.

Nové chování

V EF Core 6, '/', '\''?' a '#' jsou také řídicími znaky v id hodnotách.

Proč

Tyto znaky jsou neplatné, jak je uvedeno v Resource.Id. id Jejich použití způsobí selhání dotazů.

Omezení rizik

Vygenerovanou hodnotu můžete přepsat tak, že ji nastavíte před tím, než se entita označí jako Added:

var entry = context.Attach(entity);
entry.Property("__id").CurrentValue = "MyEntity|/\\?#";
entry.State = EntityState.Added;

Některé služby Singleton jsou nyní vymezeny.

Problém se sledováním č. 25084

Nové chování

Mnoho služeb dotazů a některé služby v době návrhu, které byly zaregistrovány jako Singleton nyní registrovány jako Scoped.

Proč

Doba života se musela změnit tak, aby umožňovala novou funkci – DefaultTypeMapping aby ovlivnila dotazy.

Životnosti služeb návrhu byly upraveny tak, aby odpovídaly životnostem služeb za běhu, aby se zabránilo chybám při použití obou.

Omezení rizik

Slouží TryAdd k registraci služeb EF Core s použitím výchozí životnosti. Používá se TryAddProviderSpecificServices jenom pro služby, které ef nepřidávají.

Nové rozhraní API pro ukládání do mezipaměti pro rozšíření, která přidávají nebo nahrazují služby

Sledování problému č. 19152

Staré chování

V EF Core 5 se GetServiceProviderHashCode vrátil long a použil se přímo jako součást klíče mezipaměti pro poskytovatele služeb.

Nové chování

GetServiceProviderHashCode nyní se vrátí int a slouží pouze k výpočtu hash kódu klíče mezipaměti pro poskytovatele služeb.

Je také potřeba implementovat, aby bylo možné určit, ShouldUseSameServiceProvider zda aktuální objekt představuje stejnou konfiguraci služby, a proto může použít stejného poskytovatele služeb.

Proč

Použití hash kódu jako součásti klíče mezipaměti způsobilo občasné kolize, které se obtížně diagnostikovaly a opravovaly. Další metoda zajišťuje, aby se stejný poskytovatel služeb používal pouze v případě potřeby.

Omezení rizik

Mnoho rozšíření nezpřístupňuje žádné možnosti, které ovlivňují registrované služby, a mohou používat následující implementaci ShouldUseSameServiceProvider:

private sealed class ExtensionInfo : DbContextOptionsExtensionInfo
{
    public ExtensionInfo(IDbContextOptionsExtension extension)
        : base(extension)
    {
    }

    ...

    public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other)
        => other is ExtensionInfo;
}

Jinak by měly být přidány další predikáty pro porovnání všech relevantních možností.

Nová procedura inicializace modelu snímků a návrhu

Problém se sledováním č. 22031

Staré chování

V EF Core 5 je potřeba vyvolat specifické konvence před tím, než byl model snímků připravený k použití.

Nové chování

IModelRuntimeInitializer byl zaveden ke skrytí některých požadovaných kroků a byl zaveden model za běhu, který neobsahuje všechna metadata migrace, takže model v době návrhu by se měl použít pro rozdíl modelu.

Proč

IModelRuntimeInitializer abstrahuje kroky dokončení modelu, takže je teď můžete změnit bez dalších zásadních změn pro uživatele.

Byl zaveden optimalizovaný model běhu za účelem zlepšení výkonu za běhu. Má několik optimalizací, z nichž jedna odebírá metadata, která se nepoužívají za běhu.

Omezení rizik

Následující fragment kódu ukazuje, jak zkontrolovat, jestli se aktuální model liší od modelu snímků:

var snapshotModel = migrationsAssembly.ModelSnapshot?.Model;

if (snapshotModel is IMutableModel mutableModel)
{
    snapshotModel = mutableModel.FinalizeModel();
}

if (snapshotModel != null)
{
    snapshotModel = context.GetService<IModelRuntimeInitializer>().Initialize(snapshotModel);
}

var hasDifferences = context.GetService<IMigrationsModelDiffer>().HasDifferences(
    snapshotModel?.GetRelationalModel(),
    context.GetService<IDesignTimeModel>().Model.GetRelationalModel());

Tento fragment kódu ukazuje, jak implementovat IDesignTimeDbContextFactory<TContext> externím vytvořením modelu a voláním UseModel:

internal class MyDesignContext : IDesignTimeDbContextFactory<MyContext>
{
    public TestContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder();
        optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DB"));

        var modelBuilder = SqlServerConventionSetBuilder.CreateModelBuilder();
        CustomizeModel(modelBuilder);
        var model = modelBuilder.Model.FinalizeModel();

        var serviceContext = new MyContext(optionsBuilder.Options);
        model = serviceContext.GetService<IModelRuntimeInitializer>().Initialize(model);
        return new MyContext(optionsBuilder.Options);
    }
}

OwnedNavigationBuilder.HasIndex vrátí jiný typ.

Problém se sledováním č. 24005

Staré chování

V EF Core 5 se vrátíIndexBuilder<TEntity>, HasIndex kde TEntity je typ vlastníka.

Nové chování

HasIndex nyní vrátí , IndexBuilder<TDependentEntity>kde TDependentEntity je vlastněný typ.

Proč

Vrácený objekt tvůrce nebyl zadán správně.

Omezení rizik

Překompilování sestavení proti nejnovější verzi EF Core bude stačit k vyřešení jakýchkoli problémů způsobených touto změnou.

DbFunctionBuilder.HasSchema(null) Přepisuje [DbFunction(Schema = "schema")]

Problém se sledováním č. 24228

Staré chování

V EF Core 5 HasSchema volání s null hodnotou neukládalo zdroj konfigurace, takže DbFunctionAttribute ho bylo možné přepsat.

Nové chování

Volání HasSchema s null hodnotou teď ukládá zdroj konfigurace a zabraňuje přepsání atributu.

Proč

Konfigurace zadaná pomocí ModelBuilder rozhraní API by neměla být přepsána datovými poznámkami.

Omezení rizik

HasSchema Odeberte volání, aby atribut nakonfigurovali schéma.

Předem inicializované navigace se přepisují hodnotami z databázových dotazů.

Problém se sledováním č. 23851

Staré chování

Navigační vlastnosti nastavené na prázdný objekt zůstaly beze změny pro sledování dotazů, ale byly přepsány pro nesledované dotazy. Představte si například následující typy entit:

public class Foo
{
    public int Id { get; set; }

    public Bar Bar { get; set; } = new(); // Don't do this.
}

public class Bar
{
    public int Id { get; set; }
}

Dotaz bez sledování, který Foo zahrnuje Bar nastavení Foo.Bar entity dotazované z databáze. Například tento kód:

var foo = context.Foos.AsNoTracking().Include(e => e.Bar).Single();
Console.WriteLine($"Foo.Bar.Id = {foo.Bar.Id}");

Vytištěno Foo.Bar.Id = 1.

Stejné spuštění dotazu pro sledování však nepřepsalo Foo.Bar entitou dotazovanou z databáze. Například tento kód:

var foo = context.Foos.Include(e => e.Bar).Single();
Console.WriteLine($"Foo.Bar.Id = {foo.Bar.Id}");

Vytištěno Foo.Bar.Id = 0.

Nové chování

V EF Core 6.0 se chování sledovacích dotazů teď shoduje s dotazy bez sledování. To znamená, že oba tyto kódy:

var foo = context.Foos.AsNoTracking().Include(e => e.Bar).Single();
Console.WriteLine($"Foo.Bar.Id = {foo.Bar.Id}");

A tento kód:

var foo = context.Foos.Include(e => e.Bar).Single();
Console.WriteLine($"Foo.Bar.Id = {foo.Bar.Id}");

Tisk Foo.Bar.Id = 1.

Proč

Existují dva důvody pro provedení této změny:

  1. Aby se zajistilo, že sledování a dotazy bez sledování mají konzistentní chování.
  2. Při dotazech databáze je vhodné předpokládat, že kód aplikace chce získat zpět hodnoty uložené v databázi.

Omezení rizik

Existují dvě omezení rizik:

  1. Nevytávejte dotazy na objekty z databáze, které by neměly být zahrnuty do výsledků. Například ve výše uvedených fragmentech kódu nepoužívejte IncludeFoo.Bar , pokud Bar by instance neměla být vrácena z databáze a zahrnuta do výsledků.
  2. Po dotazování z databáze nastavte hodnotu navigace. Například ve výše uvedených fragmentech kódu volejte foo.Bar = new() po spuštění dotazu.

Zvažte také inicializaci instancí souvisejících entit na výchozí objekty. To znamená, že související instance je nová entita, která není uložena do databáze, bez sady hodnot klíče. Pokud v databázi existuje související entita, pak jsou data v kódu v podstatě v rozporu s daty uloženými v databázi.

Neznámé hodnoty řetězců výčtu v databázi se při dotazování nepřevedou na výchozí výčt.

Problém se sledováním č. 24084

Staré chování

Vlastnosti výčtu lze mapovat na řetězcové sloupce v databázi pomocí HasConversion<string>() nebo EnumToStringConverter. Výsledkem je převod řetězcových hodnot ve sloupci na odpovídající členy typu výčtu .NET. Pokud se však hodnota řetězce neshodovala a výčtový člen, vlastnost byla nastavena na výchozí hodnotu výčtu.

Nové chování

EF Core 6.0 teď vyvolá InvalidOperationException zprávu "Nelze převést řetězcovou hodnotu '{value} z databáze na libovolnou hodnotu v mapovaném výčtu '{enumType}'".

Proč

Převodem na výchozí hodnotu může dojít k poškození databáze, pokud se entita později uloží zpět do databáze.

Omezení rizik

V ideálním případě zajistěte, aby sloupec databáze obsahoval pouze platné hodnoty. Alternativně implementujte ValueConverter staré chování.

DbFunctionBuilder.HasTranslation nyní poskytuje argumenty funkce jako IReadOnlyList místo IReadOnlyCollection.

Problém se sledováním č. 23565

Staré chování

Při konfiguraci překladu pro uživatelem definovanou funkci pomocí HasTranslation metody byly argumenty funkce poskytnuty jako IReadOnlyCollection<SqlExpression>.

Nové chování

V EF Core 6.0 jsou argumenty nyní zadány jako IReadOnlyList<SqlExpression>.

Proč

IReadOnlyList umožňuje používat indexery, takže jsou teď k argumentům snadnější přístup.

Omezení rizik

Nezaokrouhlovat. IReadOnlyList implementuje IReadOnlyCollection rozhraní, takže přechod by měl být jednoduchý.

Výchozí mapování tabulek se neodebere, když je entita namapovaná na funkci s hodnotou tabulky.

Problém se sledováním č. 23408

Staré chování

Když byla entita namapována na funkci s hodnotou tabulky, její výchozí mapování na tabulku bylo odebráno.

Nové chování

V EF Core 6.0 je entita stále namapovaná na tabulku pomocí výchozího mapování, i když je také namapovaná na funkci s hodnotou tabulky.

Proč

Funkce s hodnotou tabulky, které vracejí entity, se často používají jako pomocná rutina nebo zapouzdřují operaci vracející kolekci entit, nikoli jako striktní nahrazení celé tabulky. Cílem této změny je být více v souladu s pravděpodobným záměrem uživatele.

Omezení rizik

Mapování na tabulku je možné explicitně zakázat v konfiguraci modelu:

modelBuilder.Entity<MyEntity>().ToTable((string)null);

dotnet-ef targets .NET 6

Problém se sledováním č. 27787

Staré chování

Příkaz dotnet-ef už nějakou dobu cílí na .NET Core 3.1. To vám umožnilo používat novější verzi nástroje bez instalace novějších verzí modulu runtime .NET.

Nové chování

V EF Core 6.0.6 teď nástroj dotnet-ef nyní cílí na .NET 6. Nástroj můžete dál používat u projektů, které cílí na starší verze .NET a .NET Core, ale abyste mohli nástroj spustit, budete muset nainstalovat modul runtime .NET 6.

Proč

Sada .NET 6.0.200 SDK aktualizovala chování dotnet tool install osx-arm64 tak, aby vytvořila shim osx-x64 pro nástroje, které cílí na .NET Core 3.1. Abychom zachovali pracovní výchozí prostředí pro dotnet-ef, museli jsme ho aktualizovat na cíl .NET 6.

Omezení rizik

Pokud chcete spustit dotnet-ef bez instalace modulu runtime .NET 6, můžete nainstalovat starší verzi nástroje:

dotnet tool install dotnet-ef --version 3.1.*

IModelCacheKeyFactory implementace může být potřeba aktualizovat, aby bylo možné zpracovat ukládání do mezipaměti v době návrhu.

Problém se sledováním č. 25154

Staré chování

IModelCacheKeyFactory neměl možnost uložit model návrhu do mezipaměti odděleně od modelu modulu runtime.

Nové chování

IModelCacheKeyFactory má nové přetížení, které umožňuje, aby model návrhu byl uložen do mezipaměti odděleně od modelu modulu runtime. Při implementaci této metody může dojít k výjimce podobné následující:

System.InvalidOperationException: Požadovaná konfigurace není uložená v modelu optimalizovaném pro čtení, použijte dbContext.GetService<IDesignTimeModel>(). Model'.

Proč

Implementace zkompilovaných modelů vyžadovala oddělení doby návrhu (používané při sestavování modelu) a modulu runtime (používaného při spouštění dotazů atd.). Pokud kód modulu runtime potřebuje přístup k informacím o době návrhu, musí být model návrhu uložen do mezipaměti.

Omezení rizik

Implementujte nové přetížení. Příklad:

public object Create(DbContext context, bool designTime)
    => context is DynamicContext dynamicContext
        ? (context.GetType(), dynamicContext.UseIntProperty, designTime)
        : (object)context.GetType();

Navigace {navigation} byla v dotazu ignorována, protože oprava se automaticky naplní. Pokud jsou další navigace uvedené v části Zahrnout, budou ignorovány. Chůze zpět v zahrnutí stromu není povolena.

Sledování problému č. 4315

Staré chování

Událost CoreEventId.NavigationBaseIncludeIgnored se ve výchozím nastavení protokolovala jako upozornění.

Nové chování

Událost CoreEventId.NavigationBaseIncludeIgnored byla ve výchozím nastavení zaznamenána jako chyba a způsobí vyvolání výjimky.

Proč

Tyto vzory dotazů nejsou povolené, takže EF Core teď vyvolá upozornění, že by se dotazy měly aktualizovat.

Omezení rizik

Staré chování lze obnovit konfigurací události jako upozornění. Příklad:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.ConfigureWarnings(b => b.Warn(CoreEventId.NavigationBaseIncludeIgnored));