Zásadní změny v EF Core 5.0

Následující změny rozhraní API a chování mají potenciál přerušit stávající aplikace aktualizace na EF Core 5.0.0.

Souhrn

Zásadní změna Dopad
EF Core 5.0 nepodporuje rozhraní .NET Framework Střední
IProperty.GetColumnName() je nyní zastaralé Střední
Přesnost a škálování se vyžadují pro desetinné čárky. Střední
Povinná nebo nenulová navigace z objektu zabezpečení na závislé má různé sémantiky. Střední
Definování dotazu se nahradí metodami specifickými pro zprostředkovatele. Střední
Referenční navigace bez hodnoty null nejsou přepsány dotazy. Střední
ToView() se při migracích zachází jinak. Střední
ToTable(null) označí typ entity jako nemapovaný na tabulku. Střední
Odebrání metody HasGeometricDimension z rozšíření SQLite NTS Nízká
Cosmos: Klíč oddílu se teď přidá do primárního klíče. Nízká
Cosmos: id vlastnost přejmenována na __id Nízká
Cosmos: bajt[] je teď uložený jako řetězec base64 místo číselného pole. Nízká
Cosmos: GetPropertyName a SetPropertyName byly přejmenovány Nízká
Generátory hodnot se volají, když se stav entity změní z odpojeného na beze změny, aktualizace nebo odstranění. Nízká
IMigrationsModelDiffer teď používá IRelationalModel Nízká
Diskriminace jsou jen pro čtení Nízká
Ef specifické pro poskytovatele. Metody funkcí pro zprostředkovatele InMemory Nízká
IndexBuilder.HasName je nyní zastaralý. Nízká
Pluralizátor je nyní součástí generování zpětnou analýzu modelů. Nízká
INavigationBase nahrazuje funkci INavigation v některých rozhraních API, aby podporovala přeskočení navigace. Nízká
Některé dotazy s korelační kolekcí, které se Distinct používají nebo GroupBy už nejsou podporované Nízká
Použití kolekce typu dotazu v projekci se nepodporuje. Nízká

Středně ovlivněné změny

EF Core 5.0 nepodporuje rozhraní .NET Framework

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

Staré chování

EF Core 3.1 cílí na .NET Standard 2.0, který podporuje rozhraní .NET Framework.

Nové chování

EF Core 5.0 cílí na .NET Standard 2.1, což rozhraní .NET Framework nepodporuje. To znamená, že EF Core 5.0 nelze použít s aplikacemi rozhraní .NET Framework.

Proč

To je součástí širšího pohybu napříč týmy .NET, které se zaměřují na sjednocení s jednou cílovou architekturou .NET. Další informace najdete v budoucnosti rozhraní .NET Standard.

Omezení rizik

Aplikace rozhraní .NET Framework můžou i nadále používat EF Core 3.1, což je dlouhodobá verze podpory (LTS). Případně je možné aplikace aktualizovat tak, aby používaly .NET Core 3.1 nebo .NET 5, z nichž obě podporují .NET Standard 2.1.

IProperty.GetColumnName() je nyní zastaralé

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

Staré chování

GetColumnName() vrátil název sloupce, na který je vlastnost namapovaná.

Nové chování

GetColumnName() stále vrací název sloupce, na který je vlastnost namapovaná, ale toto chování je teď nejednoznačné, protože EF Core 5 podporuje tpT a souběžné mapování na zobrazení nebo funkci, na které by tato mapování mohla použít různé názvy sloupců pro stejnou vlastnost.

Proč

Tuto metodu jsme označili jako zastaralou, abychom uživatele provedli přesnější přetížení - GetColumnName(IProperty, StoreObjectIdentifier).

Omezení rizik

Pomocí následujícího kódu získejte název sloupce pro konkrétní tabulku:

var columnName = property.GetColumnName(StoreObjectIdentifier.Table("Users", null)));

Přesnost a škálování se vyžadují pro desetinné čárky.

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

Staré chování

EF Core normálně nenastavil přesnost a měřítko objektů SqlParameter . To znamená, že byla odeslána úplná přesnost a škálování do SQL Server, v jakém okamžiku by SQL Server zaokrouhloval na základě přesnosti a škálování sloupce databáze.

Nové chování

EF Core teď nastavuje přesnost a škálování parametrů pomocí hodnot nakonfigurovaných pro vlastnosti v modelu EF Core. To znamená, že teď probíhá zaokrouhlování v SqlClientu. V důsledku toho, pokud nakonfigurovaná přesnost a škálování neodpovídají přesnosti a škálování databáze, může se zaokrouhlování změnit.

Proč

Novější funkce SQL Server, včetně Always Encrypted, vyžadují, aby byly plně zadané omezující vlastnosti parametrů. Kromě toho SqlClient provedl změnu zaokrouhlení místo zkrátit desetinné hodnoty, čímž odpovídá chování SQL Server. Díky tomu bylo možné nastavit tyto omezující vlastnosti EF Core beze změny chování pro správně nakonfigurované desetinné čárky.

Omezení rizik

Namapujte vlastnosti desítkového čísla pomocí názvu typu, který zahrnuje přesnost a měřítko. Příklad:

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

    [Column(TypeName = "decimal(16, 5)")]
    public decimal Score { get; set; }
}

Nebo se používá HasPrecision v rozhraních API pro vytváření modelů. Příklad:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().Property(e => e.Score).HasPrecision(16, 5);
    }

Povinná nebo nenulová navigace z objektu zabezpečení na závislé má různé sémantiky.

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

Staré chování

Podle potřeby je možné nakonfigurovat jenom navigace k objektu zabezpečení. Proto použití RequiredAttribute na navigaci na závislé (entitě obsahující cizí klíč) nebo označení jako nenulovatelné by místo toho vytvořilo cizí klíč pro definující typ entity.

Nové chování

S přidanou podporou požadovaných závislých je teď možné označit libovolnou referenční navigaci podle potřeby, což znamená, že v případě uvedeném nad cizím klíčem bude definován na druhé straně relace a vlastnosti nebudou označené jako povinné.

Volání IsRequired před zadáním závislého konce je teď nejednoznačné:

modelBuilder.Entity<Blog>()
    .HasOne(b => b.BlogImage)
    .WithOne(i => i.Blog)
    .IsRequired()
    .HasForeignKey<BlogImage>(b => b.BlogForeignKey);

Proč

Nové chování je nezbytné k povolení podpory požadovaných závislých položek (viz #12100).

Omezení rizik

Odeberte RequiredAttribute z navigace na závislý a umístěte ho místo toho na navigaci do objektu zabezpečení nebo nakonfigurujte relaci v OnModelCreating:

modelBuilder.Entity<Blog>()
    .HasOne(b => b.BlogImage)
    .WithOne(i => i.Blog)
    .HasForeignKey<BlogImage>(b => b.BlogForeignKey)
    .IsRequired();

Definování dotazu se nahradí metodami specifickými pro zprostředkovatele.

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

Staré chování

Typy entit byly namapovány na definování dotazů na úrovni Core. Kdykoli byl typ entity použit v kořenovém adresáři dotazu typu entity, byl nahrazen definováním dotazu pro libovolného zprostředkovatele.

Nové chování

Rozhraní API pro definování dotazů jsou zastaralá. Byla zavedena nová rozhraní API specifická pro poskytovatele.

Proč

Při definování dotazů se při každém použití kořenového adresáře dotazu v dotazu implementovaly jako náhradní dotaz, ale mělo několik problémů:

  • Pokud definování dotazu projektuje typ entity pomocí new { ... } metody Select , pak identifikuje, že jako entita vyžadovala další práci a byla nekonzistentní s tím, jak EF Core zpracovává nominální typy v dotazu.
  • Pro relační zprostředkovatele FromSql je stále potřeba předat řetězec SQL ve formuláři výrazu LINQ.

Počáteční definování dotazů bylo zavedeno jako zobrazení na straně klienta, která se mají používat s poskytovatelem In-Memory pro entity bez klíčů (podobně jako zobrazení databáze v relačních databázích). Tato definice usnadňuje testování aplikace proti databázi v paměti. Potom se staly široce použitelnými, což bylo užitečné, ale přineslo nekonzistentní a těžko pochopitelné chování. Proto jsme se rozhodli koncept zjednodušit. Na základě LINQ jsme vytvořili exkluzivní dotaz pro In-Memory zprostředkovatele a zacházíme s nimi jinak. Další informace najdete v tomto problému.

Omezení rizik

Pro relační zprostředkovatele použijte ToSqlQuery metodu a OnModelCreating předejte řetězec SQL pro typ entity. Pro poskytovatele In-Memory použijte ToInMemoryQuery metodu a OnModelCreating předejte dotaz LINQ pro typ entity.

Referenční navigace bez hodnoty null nejsou přepsány dotazy.

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

Staré chování

V EF Core 3.1 by se odkazy na navigace dychtivě inicializovaly na hodnoty, které nejsou null, někdy přepíšou instancemi entit z databáze bez ohledu na to, jestli se hodnoty klíče shodují nebo ne. V jiných případech by ale EF Core 3.1 udělal opačnou hodnotu a ponechá stávající hodnotu, která není null.

Nové chování

Počínaje ef Core 5.0 se nenulové referenční navigace nikdy nepřepíšou instancemi vrácenými z dotazu.

Všimněte si, že inicializace navigace kolekce do prázdné kolekce je stále podporována.

Proč

Inicializace vlastnosti odkazové navigace na instanci "prázdné" entity vede k nejednoznačnému stavu. Příklad:

public class Blog
{
     public int Id { get; set; }
     public Author Author { get; set; ) = new Author();
}

Obvykle dotaz na blogy a autory nejprve vytvoří Blog instance a pak nastaví příslušné Author instance na základě dat vrácených z databáze. V tomto případě je však každá Blog.Author vlastnost již inicializována na prázdnou Author. Kromě EF Core nemá žádný způsob, jak zjistit, že tato instance je "prázdná". Takže přepsání této instance by mohlo potenciálně bezobslužně vyhodit platnou Author. EF Core 5.0 proto konzistentně nepřepíše navigaci, která je již inicializována.

Toto nové chování je také v souladu s chováním EF6 ve většině případů, i když při šetření jsme zjistili také některé případy nekonzistence v EF6.

Omezení rizik

Pokud dojde k tomuto přerušení, opravou je zastavit dychtivou inicializaci vlastností referenční navigace.

ToView() se při migracích zachází jinak.

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

Staré chování

Volání ToView(string) provedených migrací ignoruje kromě mapování na zobrazení i typ entity.

Nové chování

Teď ToView(string) označí typ entity jako nenamapovaný na tabulku kromě mapování na zobrazení. Výsledkem je první migrace po upgradu na EF Core 5, aby se pokusila odstranit výchozí tabulku pro tento typ entity, protože už není ignorována.

Proč

EF Core teď umožňuje namapovat typ entity na tabulku i zobrazení současně, takže ToView už není platným indikátorem, že by měl být ignorován migrací.

Omezení rizik

Pomocí následujícího kódu označte mapovanou tabulku jako vyloučenou z migrací:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().ToTable("UserView", t => t.ExcludeFromMigrations());
}

ToTable(null) označí typ entity jako nemapovaný na tabulku.

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

Staré chování

ToTable(null) resetuje název tabulky na výchozí hodnotu.

Nové chování

ToTable(null) teď označí typ entity jako nemapovaný na žádnou tabulku.

Proč

EF Core teď umožňuje mapovat typ entity na tabulku i zobrazení současně, takže ToTable(null) se používá k označení, že není namapovaný na žádnou tabulku.

Omezení rizik

Následujícím kódem resetujte název tabulky na výchozí, pokud není namapovaný na zobrazení nebo DbFunction:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().Metadata.RemoveAnnotation(RelationalAnnotationNames.TableName);
}

Změny s nízkým dopadem

Odebrání metody HasGeometricDimension z rozšíření SQLite NTS

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

Staré chování

HasGeometricDimension se použil k povolení dalších dimenzí (Z a M) u sloupců geometrie. To ale mělo vliv pouze na vytváření databáze. Není nutné zadat hodnoty s dalšími dimenzemi. Také nefungovalo správně při vkládání nebo aktualizaci hodnot s dalšími dimenzemi (viz č. 14257).

Nové chování

Chcete-li povolit vkládání a aktualizaci hodnot geometrie s dalšími dimenzemi (Z a M), je potřeba zadat dimenzi jako součást názvu typu sloupce. Toto rozhraní API odpovídá podrobnějšímu chování funkce AddGeometryColumn spatiaLite.

Proč

Použití HasGeometricDimension po zadání dimenze v typu sloupce je zbytečné a redundantní, takže jsme zcela odebrali HasGeometricDimension.

Omezení rizik

Slouží HasColumnType k určení dimenze:

modelBuilder.Entity<GeoEntity>(
    x =>
    {
        // Allow any GEOMETRY value with optional Z and M values
        x.Property(e => e.Geometry).HasColumnType("GEOMETRYZM");

        // Allow only POINT values with an optional Z value
        x.Property(e => e.Point).HasColumnType("POINTZ");
    });

Cosmos: Klíč oddílu se teď přidá do primárního klíče.

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

Staré chování

Vlastnost klíče oddílu byla přidána pouze do alternativního klíče, který obsahuje id.

Nové chování

Vlastnost klíče oddílu je teď také přidána do primárního klíče podle konvence.

Proč

Díky této změně je model lépe sladěný s sémantikou služby Azure Cosmos DB a zlepšuje výkon Find a některé dotazy.

Omezení rizik

Chcete-li zabránit přidání vlastnosti klíče oddílu do primárního klíče, nakonfigurujte ji v OnModelCreating.

modelBuilder.Entity<Blog>()
    .HasKey(b => b.Id);

Cosmos: id vlastnost přejmenována na __id

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

Staré chování

Stínová vlastnost mapovaná na id vlastnost JSON byla také pojmenována id.

Nové chování

Stínová vlastnost vytvořená konvencí je nyní pojmenovaná __id.

Proč

Tato změna je méně pravděpodobné, že id vlastnost koliduje s existující vlastností typu entity.

Omezení rizik

Pokud se chcete vrátit k chování 3.x, nakonfigurujte id vlastnost v OnModelCreating.

modelBuilder.Entity<Blog>()
    .Property<string>("id")
    .ToJsonProperty("id");

Cosmos: bajt[] je teď uložený jako řetězec base64 místo číselného pole.

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

Staré chování

Vlastnosti bajtů typu[] byly uloženy jako číselné pole.

Nové chování

Vlastnosti bajtů typu[] jsou nyní uloženy jako řetězec base64.

Proč

Tato reprezentace bajtů[] odpovídá očekáváním a je výchozím chováním hlavních knihoven serializace JSON.

Omezení rizik

Existující data uložená jako číselná pole budou stále správně dotazována, ale aktuálně neexistuje podporovaný způsob, jak změnit chování vložení. Pokud toto omezení blokuje váš scénář, zakomentujte tento problém.

Cosmos: GetPropertyName a SetPropertyName byly přejmenovány

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

Staré chování

Dříve se volaly GetPropertyName metody rozšíření a SetPropertyName

Nové chování

Staré rozhraní API bylo odebráno a přidány nové metody: GetJsonPropertyName, SetJsonPropertyName

Proč

Tato změna odstraňuje nejednoznačnost ohledně toho, co tyto metody konfigurují.

Omezení rizik

Použijte nové rozhraní API.

Generátory hodnot se volají, když se stav entity změní z odpojeného na beze změny, aktualizace nebo odstranění.

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

Staré chování

Generátory hodnot se volaly pouze v případě, že se stav entity změnil na Přidání.

Nové chování

Generátory hodnot se teď volají, když se stav entity změní z Odpojeno na Beze změny, Aktualizace nebo Odstranění a vlastnost obsahuje výchozí hodnoty.

Proč

Tato změna byla nezbytná ke zlepšení zkušeností s vlastnostmi, které se neuchovávají v úložišti dat a mají jejich hodnotu vygenerovanou vždy na klientovi.

Omezení rizik

Pokud chcete zabránit zavolání generátoru hodnot, před změnou stavu přiřaďte vlastnost jiné než výchozí hodnotu.

IMigrationsModelDiffer teď používá IRelationalModel

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

Staré chování

IMigrationsModelDiffer Rozhraní API bylo definováno pomocí IModel.

Nové chování

IMigrationsModelDiffer Rozhraní API teď používá IRelationalModel. Snímek modelu ale stále obsahuje pouze IModel v případě, že je tento kód součástí aplikace a Entity Framework ho nemůže změnit, aniž by se udělala větší zásadní změna.

Proč

IRelationalModel je nově přidaná reprezentace schématu databáze. Použití k vyhledání rozdílů je rychlejší a přesnější.

Omezení rizik

Pomocí následujícího kódu můžete model porovnat s modelem z snapshotcontext:

var dependencies = context.GetService<ProviderConventionSetBuilderDependencies>();
var relationalDependencies = context.GetService<RelationalConventionSetBuilderDependencies>();

var typeMappingConvention = new TypeMappingConvention(dependencies);
typeMappingConvention.ProcessModelFinalizing(((IConventionModel)modelSnapshot.Model).Builder, null);

var relationalModelConvention = new RelationalModelConvention(dependencies, relationalDependencies);
var sourceModel = relationalModelConvention.ProcessModelFinalized(snapshot.Model);

var modelDiffer = context.GetService<IMigrationsModelDiffer>();
var hasDifferences = modelDiffer.HasDifferences(
    ((IMutableModel)sourceModel).FinalizeModel().GetRelationalModel(),
    context.Model.GetRelationalModel());

Plánujeme toto prostředí vylepšit ve verzi 6.0 (viz č. 22031)

Diskriminace jsou jen pro čtení

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

Staré chování

Před voláním bylo možné změnit diskriminující hodnotu. SaveChanges

Nové chování

V předchozím případě dojde k výjimce.

Proč

EF neočekává, že se typ entity během sledování změní, takže změna diskriminující hodnoty ponechá kontext v nekonzistentním stavu, což může vést k neočekávanému chování.

Omezení rizik

Pokud je potřeba změnit diskriminující hodnotu a kontext bude okamžitě po zavolání SaveChangesodstraněn, může být diskriminace ztlumitelná:

modelBuilder.Entity<BaseEntity>()
    .Property<string>("Discriminator")
    .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);

Ef specifické pro poskytovatele. Metody funkcí pro zprostředkovatele InMemory

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

Staré chování

Ef specifické pro poskytovatele. Metody funkcí obsahovaly implementaci pro provádění klienta, která je umožňovala provádět u zprostředkovatele InMemory. Jedná se například EF.Functions.DateDiffDay o metodu specifickou pro Sql Server, která pracovala na poskytovateli InMemory.

Nové chování

Metody specifické pro poskytovatele byly aktualizovány tak, aby v textu metody vyvolaly výjimku, aby se zablokovaly vyhodnocování na straně klienta.

Proč

Metody specifické pro zprostředkovatele se mapuje na funkci databáze. Výpočty provedené funkcí mapované databáze se nedají vždy replikovat na straně klienta v LINQ. Může způsobit, že se výsledek ze serveru při provádění stejné metody v klientovi liší. Vzhledem k tomu, že se tyto metody používají v LINQ k překladu do konkrétních databázových funkcí, není potřeba je vyhodnotit na straně klienta. Vzhledem k tomu, že poskytovatel InMemory je jiná databáze, tyto metody nejsou pro tohoto poskytovatele dostupné. Při pokusu o spuštění pro zprostředkovatele InMemory nebo jiného poskytovatele, který tyto metody nepřekládá, vyvolá výjimku.

Omezení rizik

Vzhledem k tomu, že neexistuje způsob, jak přesně napodobovat chování databázových funkcí, měli byste otestovat dotazy, které obsahují, proti stejnému typu databáze jako v produkčním prostředí.

IndexBuilder.HasName je nyní zastaralý.

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

Staré chování

Dříve bylo možné definovat pouze jeden index v dané sadě vlastností. Název databáze indexu byl nakonfigurován pomocí IndexBuilder.HasName.

Nové chování

Na stejné sadě nebo vlastnostech je teď povoleno více indexů. Tyto indexy se teď rozlišují podle názvu v modelu. Podle konvence se název modelu používá jako název databáze; Ale dá se nakonfigurovat i nezávisle pomocí HasDatabaseName.

Proč

V budoucnu bychom chtěli povolit vzestupné i sestupné indexy nebo indexy s různými kolacemi na stejné sadě vlastností. Tato změna nás posune dalším krokem v tomto směru.

Omezení rizik

Veškerý kód, který dříve volal IndexBuilder.HasName, by se měl aktualizovat tak, aby volal HasDatabaseName.

Pokud váš projekt obsahuje migrace generované před EF Core verze 2.0.0, můžete upozornění v těchto souborech bezpečně ignorovat a potlačit přidáním #pragma warning disable 612, 618.

Pluralizátor je nyní součástí generování zpětnou analýzu modelů.

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

Staré chování

Dříve jste museli nainstalovat samostatný balíček pluralizátoru, aby bylo možné názvy navigace v množném čísle dbSet a kolekce a při generování typů entit DbContext a entit pomocí zpětného inženýrství schématu databáze nainstalovat názvy tabulek a s jedinečnými názvy tabulek.

Nové chování

EF Core teď obsahuje pluralizátor, který používá knihovnu Humanizer . Toto je stejná knihovna, kterou Visual Studio používá k doporučení názvů proměnných.

Proč

Použití množných forem slov pro vlastnosti kolekce a jednotného formuláře pro typy a odkazové vlastnosti je idiomaticky v .NET.

Omezení rizik

Pokud chcete pluralizátor zakázat, použijte --no-pluralize možnost zapnutou dotnet ef dbcontext scaffold nebo zapnutou -NoPluralize možnost Scaffold-DbContext.

INavigationBase nahrazuje funkci INavigation v některých rozhraních API, aby podporovala přeskočení navigace.

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

Staré chování

EF Core před 5.0 podporuje pouze jednu formu navigační vlastnosti reprezentované rozhraním INavigation .

Nové chování

EF Core 5.0 zavádí relace M:N, které používají "přeskočit navigace". Tyto funkce jsou reprezentovány ISkipNavigation rozhraním a většina funkcí INavigation byla přesunuta do společného základního rozhraní: INavigationBase.

Proč

Většina funkcí mezi normálním a přeskočením navigace je stejná. Přeskočení navigace však má jiný vztah k cizím klíčům než normální navigace, protože sady FKS nejsou přímo na konci relace, ale spíše v entitě spojení.

Omezení rizik

V mnoha případech se aplikace můžou přepnout na používání nového základního rozhraní bez dalších změn. V případech, kdy se ale navigace používá pro přístup k vlastnostem cizího klíče, by kód aplikace měl být buď omezen pouze na normální navigace, nebo aktualizovat tak, aby udělal příslušnou věc pro normální i přeskočení navigace.

Některé dotazy s korelační kolekcí, které se Distinct používají nebo GroupBy už nejsou podporované

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

Staré chování

Dříve dotazy zahrnující korelované kolekce GroupBynásledované , a také některé dotazy, které používáme Distinct k provádění.

Příklad GroupBy:

context.Parents
    .Select(p => p.Children
        .GroupBy(c => c.School)
        .Select(g => g.Key))

Distinct příklad – konkrétně Distinct dotazy, kde vnitřní projekce kolekce neobsahuje primární klíč:

context.Parents
    .Select(p => p.Children
        .Select(c => c.School)
        .Distinct())

Tyto dotazy můžou vrátit nesprávné výsledky, pokud vnitřní kolekce obsahovala nějaké duplicity, ale fungovaly správně, pokud všechny prvky v vnitřní kolekci byly jedinečné.

Nové chování

Tyto dotazy se už nepodporují. Vyvolá se výjimka, která značí, že nemáme dostatek informací pro správné sestavení výsledků.

Proč

Pro scénáře korelačních kolekcí potřebujeme znát primární klíč entity, aby bylo možné přiřadit entity kolekce správnému nadřazeného objektu. Pokud vnitřní kolekce nepoužívá GroupBy nebo Distinct, chybějící primární klíč se dá jednoduše přidat do projekce. V případě GroupBy , že to Distinct ale nejde udělat, protože by se změnil výsledek GroupBy operace nebo Distinct operace.

Zmírnění rizik

Přepište dotaz tak, aby se nepoužívaly GroupBy ani Distinct nepracoval s vnitřní kolekcí, a místo toho proveďte tyto operace na klientovi.

context.Parents
    .Select(p => p.Children.Select(c => c.School))
    .ToList()
    .Select(x => x.GroupBy(c => c).Select(g => g.Key))
context.Parents
    .Select(p => p.Children.Select(c => c.School))
    .ToList()
    .Select(x => x.Distinct())

Použití kolekce typu dotazu v projekci se nepodporuje.

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

Staré chování

V některých případech bylo možné použít kolekci typu Queryable uvnitř projekce, například jako argument konstruktoru List<T> :

context.Blogs
    .Select(b => new List<Post>(context.Posts.Where(p => p.BlogId == b.Id)))

Nové chování

Tyto dotazy se už nepodporují. Vyvolá se výjimka, která značí, že nemůžeme vytvořit objekt typu Queryable a navrhnout, jak by to mohlo být opraveno.

Proč

Objekt typu Queryable nemůžeme materializovat, takže by se místo toho automaticky vytvořil pomocí List<T> typu. To by často způsobilo výjimku z důvodu neshody typu, která nebyla velmi jasná a mohla by být pro některé uživatele překvapivá. Rozhodli jsme se rozpoznat vzor a vyvolat smysluplnější výjimku.

Zmírnění rizik

Přidejte ToList() volání za dotazovatelný objekt v projekci:

context.Blogs.Select(b => context.Posts.Where(p => p.BlogId == b.Id).ToList())