Zásadní změny v EF Core 7.0 (EF7)
Tato stránka dokumentuje rozhraní API a změny chování, které mají potenciál přerušit stávající aplikace, které se aktualizují z EF Core 6 na EF Core 7. Pokud se aktualizujete ze starší verze EF Core, nezapomeňte si projít dřívější zásadní změny:
Cílová architektura
EF Core 7.0 cílí na .NET 6. To znamená, že stávající aplikace, které cílí na .NET 6, můžou pokračovat. Aplikace, které cílí na starší verze .NET, .NET Core a .NET Framework, budou muset cílit na .NET 6 nebo .NET 7, aby používaly EF Core 7.0.
Shrnutí
Změny s vysokým dopadem
Encrypt
výchozí hodnota true
pro připojení k SQL Serveru
Problém se sledováním: SqlClient #1210
Důležité
Jedná se o závažnou změnu způsobující chybu v balíčku Microsoft.Data.SqlClient . V EF Core není nic, co by bylo možné udělat, aby se tato změna vrátila nebo zmírnit. Pokud potřebujete další dotazy nebo pomoc, nasměrujte prosím zpětnou vazbu k úložišti GitHubu Microsoft.Data.SqlClient nebo kontaktujte podpora Microsoftu Professional.
Staré chování
SqlClient připojovací řetězec používá Encrypt=False
ve výchozím nastavení. To umožňuje připojení na vývojových počítačích, kde místní server nemá platný certifikát.
Nové chování
SqlClient připojovací řetězec používá Encrypt=True
ve výchozím nastavení. To znamená, že:
- Server musí být nakonfigurovaný s platným certifikátem.
- Klient musí důvěřovat tomuto certifikátu.
Pokud tyto podmínky nejsou splněny, SqlException
bude vyvolán. Příklad:
Připojení bylo úspěšně navázáno se serverem, ale během procesu přihlášení došlo k chybě. (poskytovatel: Zprostředkovatel SSL, chyba: 0 – Řetěz certifikátů vydala autorita, která není důvěryhodná.)
Proč
Tato změna byla provedena, aby se ve výchozím nastavení buď připojení zabezpečilo, nebo se aplikace nebude připojovat.
Omezení rizik
Existují tři způsoby, jak pokračovat:
- Nainstalujte na server platný certifikát. Všimněte si, že se jedná o zahrnutý proces a vyžaduje získání certifikátu a zajištění jeho podepsání autoritou, která je klientem důvěryhodná.
- Pokud má server certifikát, ale klient ho nedůvěřuje,
TrustServerCertificate=True
umožní obejít normální mechanismus důvěryhodnosti. - Explicitně přidejte
Encrypt=False
do připojovací řetězec.
Upozorňující
Možnosti 2 i 3 opouštějí server v potenciálně nezabezpečeném stavu.
Některá upozornění znovu vyvolají výjimky.
Problém se sledováním č. 29069
Staré chování
V EF Core 6.0 byla chyba poskytovatele SQL Serveru znamenat, že některá upozornění nakonfigurovaná tak, aby ve výchozím nastavení vyvolala výjimky, byly protokolovány, ale nevyvolávaly výjimky. Tato upozornění jsou:
EventId | Popis |
---|---|
RelationalEventId.AmbientTransactionWarning | Aplikace pravděpodobně očekávala použití okolí transakce, když byla skutečně ignorována. |
RelationalEventId.IndexPropertiesBothMappedAndNotMappedToTable | Index určuje vlastnosti, z nichž některé jsou mapovány a některé z nich nejsou namapovány na sloupec v tabulce. |
RelationalEventId.IndexPropertiesMappedToNonOverlappingTables | Index určuje vlastnosti, které se mapuje na sloupce v nepřekrývajících se tabulkách. |
RelationalEventId.ForeignKeyPropertiesMappedToUnrelatedTables | Cizí klíč určuje vlastnosti, které se nemapuje na související tabulky. |
Nové chování
Počínaje EF Core 7.0 tato upozornění ve výchozím nastavení způsobí vyvolání výjimky.
Proč
Jedná se o problémy, které s velkou pravděpodobností značí chybu v kódu aplikace, který by se měl opravit.
Omezení rizik
Opravte základní problém, který je důvodem upozornění.
Můžete také změnit úroveň upozornění tak, aby byla protokolována pouze nebo potlačena zcela. Příklad:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.ConfigureWarnings(b => b.Ignore(RelationalEventId.AmbientTransactionWarning));
Tabulky SQL Serveru s triggery nebo určitými počítanými sloupci teď vyžadují speciální konfiguraci EF Core.
Problém se sledováním č. 27372
Staré chování
Předchozí verze poskytovatele SQL Serveru uložily změny prostřednictvím méně efektivní techniky, která vždy fungovala.
Nové chování
EF Core teď ve výchozím nastavení ukládá změny prostřednictvím výrazně efektivnější techniky; tato technika bohužel není na SQL Serveru podporována, pokud cílová tabulka obsahuje triggery databáze nebo určité typy počítaných sloupců. Další podrobnosti najdete v dokumentaci k SQL Serveru.
Proč
Vylepšení výkonu propojená s novou metodou jsou dostatečně důležitá, že je ve výchozím nastavení důležité je přenést na uživatele. Současně odhadujeme využití triggerů databáze nebo ovlivněných počítaných sloupců v aplikacích EF Core tak, aby byly dostatečně nízké, aby negativní důsledky způsobující změnu převažovaly nad nárůstem výkonu.
Omezení rizik
Počínaje EF Core 8.0 je možné explicitně nakonfigurovat použití klauzule OUTPUT nebo ne. Příklad:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.ToTable(tb => tb.UseSqlOutputClause(false));
}
Pokud má cílová tabulka v EF7 nebo novější aktivační událost, můžete o tom dát EF Core vědět a EF se vrátí k předchozí, méně efektivní technice. To lze provést konfigurací odpovídajícího typu entity následujícím způsobem:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.ToTable(tb => tb.HasTrigger("SomeTrigger"));
}
Všimněte si, že tím ve skutečnosti ef Core nevytvoří nebo nespravuje aktivační událost žádným způsobem – v současné době pouze informuje EF Core, že triggery jsou přítomné v tabulce. V důsledku toho je možné použít libovolný název triggeru. Zadání triggeru se dá použít k vrácení starého chování , i když v tabulce ve skutečnosti není aktivační událost.
Pokud má většina nebo všechny tabulky aktivační události, můžete se odhlásit z používání novější a efektivní techniky pro všechny tabulky modelu pomocí následujících konvencí vytváření modelu:
public class BlankTriggerAddingConvention : IModelFinalizingConvention
{
public virtual void ProcessModelFinalizing(
IConventionModelBuilder modelBuilder,
IConventionContext<IConventionModelBuilder> context)
{
foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
{
var table = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table);
if (table != null
&& entityType.GetDeclaredTriggers().All(t => t.GetDatabaseName(table.Value) == null)
&& (entityType.BaseType == null
|| entityType.GetMappingStrategy() != RelationalAnnotationNames.TphMappingStrategy))
{
entityType.Builder.HasTrigger(table.Value.Name + "_Trigger");
}
foreach (var fragment in entityType.GetMappingFragments(StoreObjectType.Table))
{
if (entityType.GetDeclaredTriggers().All(t => t.GetDatabaseName(fragment.StoreObject) == null))
{
entityType.Builder.HasTrigger(fragment.StoreObject.Name + "_Trigger");
}
}
}
}
}
Použijte konvenci týkající se přepsání DbContext
ConfigureConventions
:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Add(_ => new BlankTriggerAddingConvention());
}
To efektivně volá HasTrigger
všechny tabulky modelu místo toho, abyste je museli provádět ručně pro každou a každou tabulku.
Tabulky SQLite s triggery AFTER a virtuálními tabulkami teď vyžadují speciální konfiguraci EF Core.
Problém se sledováním č. 29916
Staré chování
Předchozí verze poskytovatele SQLite uložily změny prostřednictvím méně efektivní techniky, která vždy fungovala.
Nové chování
EF Core teď ve výchozím nastavení ukládá změny prostřednictvím efektivnější techniky pomocí klauzule RETURNING. Tato technika bohužel není podporována u SQLite, pokud cílová tabulka obsahuje triggery PO spuštění databáze, je virtuální nebo pokud se používají starší verze SQLite. Další podrobnosti najdete v dokumentaci KQLite.
Proč
Zjednodušení a zlepšení výkonu spojené s novou metodou jsou dostatečně významné, že je důležité je ve výchozím nastavení přenést uživatelům. Současně odhadujeme využití triggerů databáze a virtuálních tabulek v aplikacích EF Core tak, aby byly dostatečně nízké, aby negativní důsledky způsobující změnu převažovaly nad nárůstem výkonu.
Omezení rizik
V EF Core 8.0 byla metoda zavedena tak, UseSqlReturningClause
aby se explicitně vrátila zpět ke staršímu, méně efektivnímu SQL. Příklad:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.ToTable(tb => tb.UseSqlReturningClause(false));
}
Pokud stále používáte EF Core 7.0, můžete se vrátit ke starému mechanismu pro celou aplikaci vložením následujícího kódu do konfigurace kontextu:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlite(...)
.ReplaceService<IUpdateSqlGenerator, SqliteLegacyUpdateSqlGenerator>();
Změny se středním dopadem
Osamocené závislé položky volitelných relací se automaticky neodstraní.
Problém se sledováním č. 27217
Staré chování
Relace je nepovinná , pokud má cizí klíč hodnotu null. Nastavení cizího klíče na hodnotu null umožňuje, aby závislá entita existovala bez jakékoli související entity objektu zabezpečení. Volitelné relace je možné nakonfigurovat tak, aby používaly kaskádové odstranění, i když to není výchozí nastavení.
Volitelný závislý objekt může být od objektu zabezpečení přerušen nastavením jeho cizího klíče na hodnotu null nebo zrušením navigace do nebo z něj. V EF Core 6.0 by to způsobilo odstranění závislého objektu při konfiguraci relace pro kaskádové odstranění.
Nové chování
Počínaje EF Core 7.0 už není závislý odstraněn. Všimněte si, že pokud se objekt zabezpečení odstraní, závislý objekt se odstraní, protože kaskádové odstranění jsou pro relaci nakonfigurované.
Proč
Závislý může existovat bez jakékoli relace k objektu zabezpečení, takže přerušení relace by nemělo způsobit odstranění entity.
Omezení rizik
Závislý objekt lze explicitně odstranit:
context.Remove(blog);
Nebo SaveChanges
je možné přepsat nebo zachycovat za účelem odstranění závislých objektů bez odkazu na objekt zabezpečení. Příklad:
context.SavingChanges += (c, _) =>
{
foreach (var entry in ((DbContext)c!).ChangeTracker
.Entries<Blog>()
.Where(e => e.State == EntityState.Modified))
{
if (entry.Reference(e => e.Author).CurrentValue == null)
{
entry.State = EntityState.Deleted;
}
}
};
Kaskádové odstranění se konfiguruje mezi tabulkami při použití mapování TPT s SQL Serverem.
Problém se sledováním č. 28532
Staré chování
Při mapování hierarchie dědičnosti pomocí strategie TPT musí základní tabulka obsahovat řádek pro každou entitu uloženou bez ohledu na skutečný typ dané entity. Odstranění řádku v základní tabulce by mělo odstranit řádky ve všech ostatních tabulkách. EF Core nakonfiguruje kaskádové odstranění .
V EF Core 6.0 byla chyba poskytovatele databáze SQL Serveru znamenat, že se tyto kaskádové odstranění nevytvořila.
Nové chování
Od EF Core 7.0 se teď kaskádové odstranění vytváří pro SQL Server stejně jako vždy pro jiné databáze.
Proč
Kaskádové odstranění ze základní tabulky do dílčích tabulek v TPT umožňuje odstranění entity odstraněním jejího řádku v základní tabulce.
Omezení rizik
Ve většině případů by tato změna neměla způsobit žádné problémy. SQL Server je však velmi omezující, pokud existuje více kaskádových chování nakonfigurovaných mezi tabulkami. To znamená, že pokud existuje existující kaskádová relace mezi tabulkami v mapování TPT, sql Server může vygenerovat následující chybu:
Microsoft.Data.SqlClient.SqlException: Příkaz DELETE byl v konfliktu s omezením REFERENCE "FK_Blogs_People_OwnerId". Došlo ke konfliktu v databázi "Scratch", tabulka "dbo. Blogy", sloupec OwnerId. Příkaz byl ukončen.
Tento model například vytvoří cyklus kaskádových relací:
[Table("FeaturedPosts")]
public class FeaturedPost : Post
{
public int ReferencePostId { get; set; }
public Post ReferencePost { get; set; } = null!;
}
[Table("Posts")]
public class Post
{
public int Id { get; set; }
public string? Title { get; set; }
public string? Content { get; set; }
}
Jedna z těchto možností bude potřeba nakonfigurovat tak, aby na serveru nepoužíla kaskádové odstranění. Pokud chcete například změnit explicitní relaci:
modelBuilder
.Entity<FeaturedPost>()
.HasOne(e => e.ReferencePost)
.WithMany()
.OnDelete(DeleteBehavior.ClientCascade);
Nebo můžete změnit implicitní relaci vytvořenou pro mapování TPT:
modelBuilder
.Entity<FeaturedPost>()
.HasOne<Post>()
.WithOne()
.HasForeignKey<FeaturedPost>(e => e.Id)
.OnDelete(DeleteBehavior.ClientCascade);
Vyšší šance na zaneprázdněné nebo uzamčené chyby na SQLite při použití protokolování s předstihem pro zápis
Staré chování
Předchozí verze zprostředkovatele SQLite uložily změny prostřednictvím méně efektivní techniky, která se mohla automaticky opakovat, když byla tabulka uzamčena/zaneprázdněna a protokolování před zápisem (WAL) nebylo povoleno.
Nové chování
EF Core teď ve výchozím nastavení ukládá změny prostřednictvím efektivnější techniky pomocí klauzule RETURNING. Tato technika bohužel nemůže při zaneprázdnění nebo uzamčení automaticky opakovat opakování. V aplikaci s více vlákny (jako je webová aplikace) nepoužívá protokolování s předstihem pro zápis, je běžné, že k těmto chybám dochází.
Proč
Zjednodušení a zlepšení výkonu spojené s novou metodou jsou dostatečně významné, že je důležité je ve výchozím nastavení přenést uživatelům. Databáze vytvořené ef Core také ve výchozím nastavení umožňují protokolování s předstihem zápisu. Tým SQLite také ve výchozím nastavení doporučuje povolit protokolování s předstihem pro zápis.
Omezení rizik
Pokud je to možné, měli byste povolit protokolování s předstihem zápisu do databáze. Pokud jste databázi vytvořili ef, mělo by se jednat o tento případ. Pokud ne, můžete povolit protokolování s předstihem zápisu spuštěním následujícího příkazu.
PRAGMA journal_mode = 'wal';
Pokud z nějakého důvodu nemůžete povolit protokolování s předstihem pro zápis, můžete se vrátit ke starému mechanismu pro celou aplikaci vložením následujícího kódu do konfigurace kontextu:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlite(...)
.ReplaceService<IUpdateSqlGenerator, SqliteLegacyUpdateSqlGenerator>();
Změny s nízkým dopadem
Je možné, že je potřeba nakonfigurovat vlastnosti klíče s porovnávačem hodnot zprostředkovatele.
Problém se sledováním č. 27738
Staré chování
V EF Core 6.0 se hodnoty klíčů převzaté přímo z vlastností typů entit použily k porovnání hodnot klíčů při ukládání změn. To by využilo jakýkoli vlastní porovnávač hodnot nakonfigurovaný pro tyto vlastnosti.
Nové chování
Od EF Core 7.0 se pro tato porovnání používají hodnoty databáze. Tento "prostě funguje" pro velkou většinu případů. Pokud však vlastnosti používaly vlastní porovnávací nástroj a tento porovnávač nelze použít na hodnoty databáze, může být potřeba "porovnávač hodnot zprostředkovatele", jak je znázorněno níže.
Proč
Různé dělení entit a rozdělení tabulek můžou vést k tomu, že několik vlastností namapovaných na stejný sloupec databáze a naopak. To vyžaduje porovnání hodnot po převodu na hodnotu, která se použije v databázi.
Omezení rizik
Nakonfigurujte porovnávač hodnot zprostředkovatele. Představte si například případ, kdy se objekt hodnoty používá jako klíč, a porovnávač pro tento klíč používá porovnání řetězců bez rozlišování velkých a malých písmen:
var blogKeyComparer = new ValueComparer<BlogKey>(
(l, r) => string.Equals(l.Id, r.Id, StringComparison.OrdinalIgnoreCase),
v => v.Id.ToUpper().GetHashCode(),
v => v);
var blogKeyConverter = new ValueConverter<BlogKey, string>(
v => v.Id,
v => new BlogKey(v));
modelBuilder.Entity<Blog>()
.Property(e => e.Id).HasConversion(
blogKeyConverter, blogKeyComparer);
Hodnoty databáze (řetězce) nemohou přímo použít porovnávač definovaný pro BlogKey
typy. Proto musí být nakonfigurovaný porovnávač zprostředkovatele pro porovnávání řetězců bez rozlišování velkých a malých písmen:
var caseInsensitiveComparer = new ValueComparer<string>(
(l, r) => string.Equals(l, r, StringComparison.OrdinalIgnoreCase),
v => v.ToUpper().GetHashCode(),
v => v);
var blogKeyComparer = new ValueComparer<BlogKey>(
(l, r) => string.Equals(l.Id, r.Id, StringComparison.OrdinalIgnoreCase),
v => v.Id.ToUpper().GetHashCode(),
v => v);
var blogKeyConverter = new ValueConverter<BlogKey, string>(
v => v.Id,
v => new BlogKey(v));
modelBuilder.Entity<Blog>()
.Property(e => e.Id).HasConversion(
blogKeyConverter, blogKeyComparer, caseInsensitiveComparer);
Kontrola omezení a dalších omezujících vlastností tabulky jsou teď v tabulce nakonfigurované.
Problém se sledováním č. 28205
Staré chování
V EF Core 6.0 , HasCheckConstraint
a HasComment
IsMemoryOptimized
byly volány přímo v tvůrci typů entit. Příklad:
modelBuilder
.Entity<Blog>()
.HasCheckConstraint("CK_Blog_TooFewBits", "Id > 1023");
modelBuilder
.Entity<Blog>()
.HasComment("It's my table, and I'll delete it if I want to.");
modelBuilder
.Entity<Blog>()
.IsMemoryOptimized();
Nové chování
Počínaje EF Core 7.0 se místo toho volají tyto metody v tvůrci tabulek:
modelBuilder
.Entity<Blog>()
.ToTable(b => b.HasCheckConstraint("CK_Blog_TooFewBits", "Id > 1023"));
modelBuilder
.Entity<Blog>()
.ToTable(b => b.HasComment("It's my table, and I'll delete it if I want to."));
modelBuilder
.Entity<Blog>()
.ToTable(b => b.IsMemoryOptimized());
Existující metody byly označeny jako Obsolete
. V současné době mají stejné chování jako nové metody, ale budou odebrány v budoucí verzi.
Proč
Tyto omezující vlastnosti se vztahují pouze na tabulky. Nebudou použity na žádná mapovaná zobrazení, funkce ani uložené procedury.
Omezení rizik
Použijte metody tvůrce tabulek, jak je znázorněno výše.
Navigace z nových entit na odstraněné entity nejsou opravené.
Problém se sledováním č. 28249
Staré chování
V EF Core 6.0, když je nová entita sledována buď ze sledovacího dotazu, nebo připojením k DbContext
, pak navigace do a ze souvisejících entit veDeleted
stavu jsou opraveny.
Nové chování
Počínaje EF Core 7.0 nejsou navigace na entitách a z Deleted
entit opraveny.
Proč
Jakmile je entita označená jako Deleted
zřídka, dává smysl ji přidružit k neodstraněným entitě.
Omezení rizik
Dotazování nebo připojení entit před označením entit jako Deleted
nebo ručním nastavením navigačních vlastností na odstraněnou entitu a z ní.
Použití FromSqlRaw
a související metody od nesprávného poskytovatele vyvolá metodu use-the-correct-method.
Problém se sledováním č. 26502
Staré chování
V EF Core 6.0 může při použití relačního zprostředkovatele použít metodu rozšíření Azure Cosmos DB FromSqlRaw nebo metodu relačního FromSqlRaw rozšíření při použití zprostředkovatele Azure Cosmos DB bezobslužně selhat. Stejně tak použití relačních metod na zprostředkovateli v paměti je bezobslužné no-op.
Nové chování
Počínaje EF Core 7.0 vyvolá výjimka pomocí metody rozšíření navržené pro jednoho zprostředkovatele na jiném poskytovateli.
Proč
Správná metoda rozšíření musí být použita, aby fungovala správně ve všech situacích.
Omezení rizik
Použijte správnou metodu rozšíření pro zprostředkovatele, který se používá. Pokud se odkazuje na více zprostředkovatelů, zavolejte metodu rozšíření jako statickou metodu. Příklad:
var result = await CosmosQueryableExtensions.FromSqlRaw(context.Blogs, "SELECT ...").ToListAsync();
Nebo:
var result = await RelationalQueryableExtensions.FromSqlRaw(context.Blogs, "SELECT ...").ToListAsync();
Vygenerované generování už nevolá OnConfiguring
IsConfigured
Staré chování
V EF Core 6.0 DbContext
typ vygenerovaný z existující databáze obsahoval volání IsConfigured
. Příklad:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
optionsBuilder.UseNpgsql("MySecretConnectionString");
}
}
Nové chování
Od EF Core 7.0 už není volání IsConfigured
zahrnuté.
Proč
Existují velmi omezené scénáře, kdy je zprostředkovatel databáze v některých případech nakonfigurovaný uvnitř dbContext, ale pouze v případě, že kontext ještě není nakonfigurovaný. OnConfiguring
Místotohoch připojovací řetězec ch Proto se za to, že odebrání tohoto kódu bylo považováno za užitečné, zejména vzhledem k tomu, že --no-onconfiguring
příznak (.NET CLI) nebo -NoOnConfiguring
(konzola sady Visual Studio Správce balíčků) lze použít k zabránění generování uživatelského rozhraní OnConfiguring
metody a že přizpůsobitelné šablony existují pro přidání zpětIsConfigured
, pokud je skutečně potřeba.
Omezení rizik
Buď:
--no-onconfiguring
Při generování z existující databáze použijte argument (.NET CLI) nebo-NoOnConfiguring
(konzola sady Visual Studio Správce balíčků).- Přizpůsobte si šablony T4 a přidejte zpět volání .
IsConfigured