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ě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é
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
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.
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
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.
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 snapshot
context
:
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í SaveChanges
odstraně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.
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.
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())