Zásadní změny v EF Core 5.0

Následující změny rozhraní API a chování můžou narušit stávající aplikace, které se aktualizují na EF Core 5.0.0.

Souhrn

Změna způsobující chybu Dopad
EF Core 5.0 nepodporuje rozhraní .NET Framework Medium
IProperty.GetColumnName() je teď zastaralé Medium
Přesnost a měřítko jsou vyžadovány pro desetinná místa. Medium
Požadovaná nebo nenulová navigace z objektu zabezpečení na závislé má odlišnou sémantiku. Medium
Definování dotazu se nahradí metodami specifickými pro zprostředkovatele. Medium
Nenulové referenční navigace nejsou přepsány dotazy Medium
S toView() se migracemi zachází jinak. Medium
ToTable(null) označuje typ entity jako nemapovaný na tabulku. Medium
Odebrání metody HasGeometricDimension z rozšíření SQLite NTS nízkou
Azure Cosmos DB: Klíč oddílu se teď přidá do primárního klíče. nízkou
Azure Cosmos DB: id vlastnost přejmenována na __id nízkou
Azure Cosmos DB: Bajt[] je teď uložený jako řetězec base64 místo číselného pole. nízkou
Azure Cosmos DB: Byly přejmenovány GetPropertyName a SetPropertyName. nízkou
Generátory hodnot se volají, když se stav entity změní z Odpojeno na Nezměněné, Aktualizované nebo Odstraněné nízkou
IMigrationsModelDiffer teď používá model IRelationalModel. nízkou
Diskriminátor je jen pro čtení nízkou
EF specifický pro zprostředkovatele. Vyvolání metod functions pro zprostředkovatele InMemory nízkou
IndexBuilder.HasName je teď zastaralý. nízkou
Pro generování modelů s zpětnou analýzou je teď součástí pluralizátoru. nízkou
INavigationBase nahrazuje INavigation v některých rozhraních API, aby podporovala přeskočení navigace. nízkou
Některé dotazy s korelovanou kolekcí, které se Distinct používají nebo GroupBy již nejsou podporovány nízkou
Použití kolekce typu dotazovatelného v projekci se nepodporuje. nízkou

Změny se středním dopadem

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, což je podporováno rozhraním .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č

Toto je součástí širšího pohybu napříč týmy .NET zaměřeným 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). Alternativně 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 teď zastaralé

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

Staré chování

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

Nové chování

GetColumnName() stále vrací název sloupce, na který je vlastnost namapovaná, ale toto chování je nyní nejednoznačné, protože EF Core 5 podporuje TPT a současné mapování na zobrazení nebo funkci, kde 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

Pokud je typ entity mapován pouze na jednu tabulku a nikdy na zobrazení, funkce nebo více tabulek, GetColumnBaseName(IReadOnlyProperty) lze ho použít v EF Core 5.0 a 6.0 k získání názvu tabulky. Příklad:

var columnName = property.GetColumnBaseName();

V EF Core 7.0 to lze znovu nahradit novým GetColumnName, který se chová jako originál pro jednoduché mapování pouze jedné tabulky.

Pokud je možné typ entity namapovat na zobrazení, funkce nebo více tabulek, StoreObjectIdentifier musí být získána identita tabulky, zobrazení nebo funkce. To se pak dá použít k získání názvu sloupce pro daný objekt úložiště. Příklad:

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

Přesnost a měřítko jsou vyžadovány pro desetinná místa.

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

Staré chování

EF Core obvykle nenastavila přesnost a škálování SqlParameter objektů. To znamená, že se na SQL Server odeslala úplná přesnost a škálování, v jakém okamžiku by sql Server zaokrouhlil 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 SqlClient. V důsledku toho platí, že pokud nakonfigurovaná přesnost a škálování neodpovídají přesnosti a škálování databáze, může se zaokrouhlování, které se zobrazí, změnit.

Proč

Novější funkce SQL Serveru, včetně funkce Always Encrypted, vyžadují, aby byly plně zadané omezující vlastnosti parametrů. Kromě toho SqlClient provedl změnu zaokrouhlení namísto zkrácení desetinných hodnot, čímž se shoduje s chováním SQL Serveru. Díky tomu může EF Core nastavit tyto omezující vlastnosti beze změny chování pro správně nakonfigurované desetinné čárky.

Omezení rizik

Namapujte vlastnosti desetinných míst 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 použijte 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);
    }

Požadovaná nebo nenulová navigace z objektu zabezpečení na závislé má odlišnou sémantiku.

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

Staré chování

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

Nové chování

S přidanou podporou požadovaných závislostí je nyní možné označit jakoukoli 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čeny 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 do závislého objektu a umístěte ho na navigaci na objekt 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 definujícím dotazem pro libovolného zprostředkovatele.

Nové chování

Rozhraní API pro definování dotazu jsou zastaralá. Zavedla se 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, měl několik problémů:

  • Pokud je definováním dotazu projektování typu entity pomocí new { ... }Select metody, pak identifikujete, že jako entita vyžadovala další práci a nekonzistentně s tím, jak EF Core zpracovává nominální typy v dotazu.
  • U relačních zprostředkovatelů 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žít s zprostředkovatelem v paměti pro entity bez klíčů (podobně jako zobrazení databáze v relačních databázích). Tato definice usnadňuje testování aplikace v databázi v paměti. Poté se staly široce použitelnými, což bylo užitečné, ale přineslo nekonzistentní a obtížné pochopit chování. Proto jsme se rozhodli koncept zjednodušit. Na základě LINQ jsme definovali dotaz výhradně pro poskytovatele v paměti a nakládáme s nimi jinak. Další informace najdete v tomto problému.

Omezení rizik

U relačních zprostředkovatelů použijte ToSqlQuery metodu a OnModelCreating předejte řetězec SQL, který se má použít pro typ entity. Pro zprostředkovatele v paměti použijte ToInMemoryQuery metodu a OnModelCreating předejte dotaz LINQ, který se použije pro typ entity.

Nenulové referenční navigace nejsou přepsány dotazy

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

Staré chování

V EF Core 3.1 by se někdy odkazové navigace inicializovaly na hodnoty, které nemají hodnotu null, přepsaly instance entit z databáze bez ohledu na to, jestli se hodnoty klíče shodovaly nebo ne. V jiných případech by však EF Core 3.1 udělal opačnou hodnotu a ponechá existující hodnotu, která není null.

Nové chování

Počínaje EF Core 5.0 se nenulové referenční navigace nikdy nepřepíší 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 navigace odkazu na "prázdnou" instanci entity má za následek nejednoznačný stav. 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. Proto EF Core 5.0 nyní konzistentně nepřepíše navigaci, která je již inicializována.

Toto nové chování je ve většině případů v souladu s chováním EF6, 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.

S toView() se migracemi zachází jinak.

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

Staré chování

Voláním ToView(string) migrace se kromě mapování entity na zobrazení ignoruje i typ entity.

Nové chování

Teď ToView(string) označí typ entity jako nemapovaný 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 se měly při migracích ignorovat.

Omezení rizik

K označení mapované tabulky jako vyloučené z migrací použijte následující kód:

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

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

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

Staré chování

ToTable(null) by resetoval název tabulky na výchozí.

Nové chování

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

Proč

EF Core teď umožňuje namapovat 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

Pomocí následujícího kódu obnovte 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

Sledování problému č. 14257

Staré chování

HasGeometricDimension se použil k povolení dalších dimenzí (Z a M) u sloupců geometrie. To však mělo vliv pouze na vytváření databáze. Pro dotazování hodnot s dalšími dimenzemi nebylo nutné ji zadávat. Při vkládání nebo aktualizaci hodnot s dalšími dimenzemi také nefungovalo správně (viz #14257).

Nové chování

Chcete-li povolit vkládání a aktualizaci hodnot geometrie s dalšími rozměry (Z a M), musí být dimenze zadána jako součást názvu typu sloupce. Toto rozhraní API se blíže shoduje se základním chováním 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");
    });

Azure Cosmos DB: 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 nyní také přidána do primárního klíče podle konvence.

Proč

Díky této změně je model lépe v souladu 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 ho v OnModelCreating.

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

Azure Cosmos DB: 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í pojmenována __id.

Proč

Díky této změně je méně pravděpodobné, že id vlastnost koliduje s existující vlastností typu entity.

Omezení rizik

Chcete-li se vrátit k chování 3.x, nakonfigurujte id vlastnost v OnModelCreating.

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

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

Sledování problému č. 17306

Staré chování

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

Nové chování

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

Proč

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

Omezení rizik

Stávající data uložená jako číselná pole se budou pořád dotazovat správně, ale v současné době neexistuje podporovaný způsob, jak změnit chování při vkládání. Pokud toto omezení blokuje váš scénář, komentář k tomuto problému

Azure Cosmos DB: Byly přejmenovány GetPropertyName a SetPropertyName.

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

Staré chování

Dříve byly volány 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 odebere 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 Odpojeno na Nezměněné, Aktualizované nebo Odstraněné

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

Staré chování

Generátory hodnot byly volány pouze v případech, kdy se stav entity změnil na Přidaný.

Nové chování

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

Proč

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

Omezení rizik

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

IMigrationsModelDiffer teď používá model 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 došlo k větší zásadní změně.

Proč

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

Omezení rizik

Pomocí následujícího kódu porovnejte model 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)

Diskriminátor je jen pro čtení

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

Staré chování

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

Nové chování

Ve výše uvedeném případě dojde k výjimce.

Proč

EF neočekává, že se typ entity změní, zatímco se stále sleduje, 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 diskriminátor ztlumitelný:

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

EF specifický pro zprostředkovatele. Vyvolání metod functions pro zprostředkovatele InMemory

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

Staré chování

EF specifický pro zprostředkovatele. Metody functions obsahovaly implementaci pro spouštění klientů, což umožnilo jejich spuštění u zprostředkovatele InMemory. Jedná se například EF.Functions.DateDiffDay o metodu specifickou pro Sql Server, která pracovala na zprostředkovateli InMemory.

Nové chování

Metody specifické pro zprostředkovatele byly aktualizovány tak, aby v těle metody vyvolaly výjimku, aby se zablokovaly vyhodnocování na straně klienta.

Proč

Metody specifické pro zprostředkovatele se mapuje na databázovou funkci. Výpočet provedený funkcí mapované databáze nejde vždy replikovat na straně klienta v LINQ. Může to 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í, nemusí se vyhodnocovat na straně klienta. Protože zprostředkovatel 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 obsahující je proti stejnému druhu databáze jako v produkčním prostředí.

IndexBuilder.HasName je teď zastaralý.

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

Staré chování

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

Nové chování

Ve 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 také nezávisle pomocí HasDatabaseName.

Proč

V budoucnu bychom chtěli povolit vzestupné i sestupné indexy nebo indexy s různými kolacemi ve 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 místo toho volal HasDatabaseName.

Pokud váš projekt zahrnuje 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.

Pro generování modelů s zpětnou analýzou je teď součástí pluralizátoru.

Sledování problému č. 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 typů entit pomocí zpětné analýzy schématu databáze nainstalovat názvy tabulek a s jednotným generováním názvů 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čování názvů proměnných.

Proč

Použití množného čísla slov pro vlastnosti kolekce a jednotné formuláře pro typy a odkazové vlastnosti je idiotika v .NET.

Omezení rizik

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

INavigationBase nahrazuje 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 verzí 5.0 podporovala pouze jednu formu navigační vlastnosti reprezentované rozhraním INavigation .

Nové chování

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

Proč

Většina funkcí mezi normálními a přeskočením navigace je stejná. Přeskočení navigace ale má jiný vztah k cizím klíčům než normální navigace, protože sady FK 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 navigace používá pro přístup k vlastnostem cizího klíče, by měl být kód aplikace buď omezen pouze na normální navigace, nebo aktualizovat, aby udělal příslušnou věc pro normální i přeskočení navigace.

Některé dotazy s korelovanou kolekcí, které se Distinct používají nebo GroupBy již nejsou podporovány

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

Staré chování

Dříve byly dotazy zahrnující korelované kolekce, za kterými následuje GroupBy, a také některé dotazy, pomocí Distinct kterých jsme mohli provádět.

Příklad GroupBy:

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

Distinct příklad – konkrétně Distinct dotazy, kdy projekce vnitřní 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 byly všechny prvky v vnitřní kolekci 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 korelovaných kolekcí potřebujeme znát primární klíč entity, aby bylo možné přiřadit entity kolekce ke správnému nadřazení objektu. Pokud se 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 a Distinct není možné ho provést, protože by se změnil výsledek operace nebo Distinct operaceGroupBy.

Omezení rizik

Přepište dotaz tak, aby se nepoužívaly GroupBy nebo Distinct nepracoval s vnitřní kolekcí, a místo toho proveďte tyto operace v 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 dotazovatelného v projekci se nepodporuje.

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

Staré chování

Dříve bylo možné v některých případech použít kolekci typu Queryable v projekci, 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 bylo možné tuto chybu opravit.

Proč

Objekt typu s možností dotazu nemůžeme materializovat, takže by se místo toho automaticky vytvořily pomocí List<T> typu. To často způsobí 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.

Omezení rizik

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

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