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í
* 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 ContactInfo
Address
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 Customer
vytvoř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:
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(); });
Ujistěte se, že závislý obsahuje aspoň jednu požadovanou vlastnost.
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.
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.
Azure Cosmos DB: Související typy entit se zjistí jako vlastněné
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í 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
Sdružování připojení 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 |
Cascade | KASKÁDA |
ClientCascade | |
SetNull | NASTAVIT HODNOTU NULL |
ClientSetNull |
Změny generování uživatelského rozhraní jsou následující.
PŘI ODSTRANĚNÍ | OnDelete() |
---|---|
ŽÁDNÁ AKCE | ClientSetNull |
OMEZIT | |
KASKÁDA | 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
Pokud chcete 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 - odolnosti připojení – 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
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)
potlačuje [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:
- Aby se zajistilo, že sledování a dotazy bez sledování mají konzistentní chování.
- 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:
- 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
Include
Foo.Bar
, pokudBar
by instance neměla být vrácena z databáze a zahrnuta do výsledků. - 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.
NavigationBaseIncludeIgnored
je teď ve výchozím nastavení chyba.
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));