Novinky v EF Core 5.0
Následující seznam obsahuje hlavní nové funkce EF Core 5.0. Úplný seznamproblémůch
Jako hlavní verze EF Core 5.0 obsahuje také několik zásadních změn, což jsou vylepšení rozhraní API nebo změny chování, které můžou mít negativní dopad na stávající aplikace.
N:N
EF Core 5.0 podporuje relace M:N bez explicitního mapování tabulky spojení.
Představte si například tyto typy entit:
public class Post
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int Id { get; set; }
public string Text { get; set; }
public ICollection<Post> Posts { get; set; }
}
EF Core 5.0 to rozpozná jako relaci M:N podle konvence a automaticky vytvoří PostTag
tabulku spojení v databázi. Data je možné dotazovat a aktualizovat bez explicitního odkazu na tabulku spojení, což výrazně zjednodušuje kód. V případě potřeby je možné tabulku spojení přizpůsobit a dotazovat explicitně.
Další informace najdete v úplné dokumentaci k M:N.
Rozdělené dotazy
Od EF Core 3.0 EF Core vždy vygeneruje jeden dotaz SQL pro každý dotaz LINQ. Tím zajistíte konzistenci dat vrácených v rámci omezení používaného režimu transakce. To se ale může velmi zpomalit, když dotaz použije Include
nebo projekci k vrácení více souvisejících kolekcí.
EF Core 5.0 teď umožňuje rozdělit jeden dotaz LINQ včetně souvisejících kolekcí do několika dotazů SQL. To může výrazně zvýšit výkon, ale může vést k nekonzistence výsledků vrácených v případě, že se data mezi těmito dvěma dotazy změní. Serializovatelné nebo snímkové transakce lze použít ke zmírnění tohoto omezení a dosažení konzistence s rozdělenými dotazy, ale to může přinést jiné náklady na výkon a rozdíl chování.
Představte si například dotaz, který načítá dvě úrovně souvisejících kolekcí pomocí Include
:
var artists = context.Artists
.Include(e => e.Albums)
.ToList();
Ef Core ve výchozím nastavení při použití zprostředkovatele SQLite vygeneruje následující SQL:
SELECT a."Id", a."Name", a0."Id", a0."ArtistId", a0."Title"
FROM "Artists" AS a
LEFT JOIN "Album" AS a0 ON a."Id" = a0."ArtistId"
ORDER BY a."Id", a0."Id"
Při rozdělených dotazech se místo toho vygeneruje následující SQL:
SELECT a."Id", a."Name"
FROM "Artists" AS a
ORDER BY a."Id"
SELECT a0."Id", a0."ArtistId", a0."Title", a."Id"
FROM "Artists" AS a
INNER JOIN "Album" AS a0 ON a."Id" = a0."ArtistId"
ORDER BY a."Id"
Rozdělené dotazy lze povolit umístěním nového AsSplitQuery
operátora kdekoli v dotazu LINQ nebo globálně v modelu OnConfiguring
. Další informace najdete v úplné dokumentaci k rozdělených dotazech.
Jednoduché protokolování a vylepšená diagnostika
EF Core 5.0 představuje jednoduchý způsob, jak nastavit protokolování prostřednictvím nové LogTo
metody. Následující zpráva způsobí zápis zpráv protokolování do konzoly, včetně všech SQL vygenerovaných EF Core:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(Console.WriteLine);
Kromě toho je teď možné volat ToQueryString
jakýkoli dotaz LINQ a načíst SQL, který by dotaz spustil:
Console.WriteLine(
ctx.Artists
.Where(a => a.Name == "Pink Floyd")
.ToQueryString());
Nakonec byly různé typy EF Core vybaveny vylepšenou DebugView
vlastností, která poskytuje podrobný pohled na vnitřní vlastnosti. Můžete se například podívat, ChangeTracker.DebugView které entity se v daném okamžiku sledují přesně.
Další informace najdete v dokumentaci k protokolování a zachycení.
Filtrované zahrnutí
Metoda Include
teď podporuje filtrování zahrnutých entit:
var blogs = context.Blogs
.Include(e => e.Posts.Where(p => p.Title.Contains("Cheese")))
.ToList();
Tento dotaz vrátí blogy společně s každým přidruženým příspěvkem, ale pouze v případě, že název příspěvku obsahuje "Sýr".
Další informace najdete v úplné dokumentaci k vyfiltrovaným zahrnutím.
Mapování tabulek na typ (TPT)
EF Core ve výchozím nastavení mapuje hierarchii dědičnosti typů .NET na jednoúčelovou tabulku databáze. To se označuje jako mapování TPH (table-per-hierarchy). EF Core 5.0 také umožňuje mapování jednotlivých typů .NET v hierarchii dědičnosti na jinou tabulku databáze; označuje se jako mapování typu tabulky (TPT).
Představte si například tento model s mapovanou hierarchií:
public class Animal
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Cat : Animal
{
public string EducationLevel { get; set; }
}
public class Dog : Animal
{
public string FavoriteToy { get; set; }
}
Pomocí TPT se vytvoří tabulka databáze pro každý typ v hierarchii:
CREATE TABLE [Animals] (
[Id] int NOT NULL IDENTITY,
[Name] nvarchar(max) NULL,
CONSTRAINT [PK_Animals] PRIMARY KEY ([Id])
);
CREATE TABLE [Cats] (
[Id] int NOT NULL,
[EducationLevel] nvarchar(max) NULL,
CONSTRAINT [PK_Cats] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Cats_Animals_Id] FOREIGN KEY ([Id]) REFERENCES [Animals] ([Id]) ON DELETE NO ACTION,
);
CREATE TABLE [Dogs] (
[Id] int NOT NULL,
[FavoriteToy] nvarchar(max) NULL,
CONSTRAINT [PK_Dogs] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Dogs_Animals_Id] FOREIGN KEY ([Id]) REFERENCES [Animals] ([Id]) ON DELETE NO ACTION,
);
Další informace najdete v úplné dokumentaci k TPT.
Flexibilní mapování entit
Typy entit se běžně mapují na tabulky nebo zobrazení, aby EF Core při dotazování na tento typ přetáhl obsah tabulky nebo zobrazení. EF Core 5.0 přidává další možnosti mapování, kdy entitu lze mapovat na dotaz SQL (označovaný jako "definování dotazu") nebo na funkci s hodnotou tabulky (TVF):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>().ToSqlQuery(
@"SELECT Id, Name, Category, BlogId FROM posts
UNION ALL
SELECT Id, Name, ""Legacy"", BlogId from legacy_posts");
modelBuilder.Entity<Blog>().ToFunction("BlogsReturningFunction");
}
Funkce hodnotné tabulkou lze také mapovat na metodu .NET místo na DbSet, což umožňuje předávání parametrů; mapování lze nastavit pomocí HasDbFunction.
Nakonec je teď možné při dotazování (nebo na funkci nebo definování dotazu) namapovat entitu na zobrazení, ale při aktualizaci na tabulku:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Blog>()
.ToTable("Blogs")
.ToView("BlogsView");
}
Typy entit sdíleného typu a kontejnery vlastností
EF Core 5.0 umožňuje mapování stejného typu CLR na více různých typů entit; tyto typy se označují jako typy entit sdíleného typu. I když se s touto funkcí dá použít jakýkoli typ CLR, nabízí .NET Dictionary
obzvláště atraktivní případ použití, který nazýváme "kontejnery vlastností":
public class ProductsContext : DbContext
{
public DbSet<Dictionary<string, object>> Products => Set<Dictionary<string, object>>("Product");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.SharedTypeEntity<Dictionary<string, object>>("Product", b =>
{
b.IndexerProperty<int>("Id");
b.IndexerProperty<string>("Name").IsRequired();
b.IndexerProperty<decimal>("Price");
});
}
}
Tyto entity se pak dají dotazovat a aktualizovat stejně jako běžné typy entit s vlastním vyhrazeným typem CLR. Další informace najdete v dokumentaci k kontejneru nemovitostí.
Povinné 1:1 závislé
V EF Core 3.1 byl závislý konec relace 1:1 vždy považován za volitelný. To bylo nejjevnější při použití vlastněných entit, protože byl v databázi vytvořen sloupec vlastněné entity jako null, i když byly v modelu nakonfigurovány podle potřeby.
V EF Core 5.0 je možné nakonfigurovat navigaci na vlastněnou entitu jako požadovanou závislost. Příklad:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>(b =>
{
b.OwnsOne(e => e.HomeAddress,
b =>
{
b.Property(e => e.City).IsRequired();
b.Property(e => e.Postcode).IsRequired();
});
b.Navigation(e => e.HomeAddress).IsRequired();
});
}
DbContextFactory
EF Core 5.0 zavádí AddDbContextFactory
a AddPooledDbContextFactory
zaregistruje továrnu pro vytváření instancí DbContext v kontejneru injektáže závislostí aplikace (D.I.). To může být užitečné, když kód aplikace potřebuje vytvořit a hodit kontextové instance ručně.
services.AddDbContextFactory<SomeDbContext>(b =>
b.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"));
V tomto okamžiku je možné aplikační služby, jako jsou ASP.NET kontrolery Core, následně vloženy do IDbContextFactory<TContext>
instance instancí kontextových instancí:
public class MyController : Controller
{
private readonly IDbContextFactory<SomeDbContext> _contextFactory;
public MyController(IDbContextFactory<SomeDbContext> contextFactory)
=> _contextFactory = contextFactory;
public void DoSomeThing()
{
using (var context = _contextFactory.CreateDbContext())
{
// ...
}
}
}
Další informace najdete v úplné dokumentaci k DbContextFactory.
Opětovné sestavení tabulek SQLite
Ve srovnání s jinými databázemi je SQLite relativně omezený ve svých možnostech manipulace se schématy; Například vyřazení sloupce z existující tabulky se nepodporuje. EF Core 5.0 tato omezení obejít tak, že automaticky vytvoří novou tabulku, zkopíruje data ze staré tabulky, přepnou starou tabulku a přejmenuje novou. Tato tabulka znovu sestaví a umožní bezpečné použití dříve nepodporovaných operací migrace.
Podrobnosti o tom, které operace migrace jsou nyní podporovány prostřednictvím opětovného sestavení tabulky, najdete na této stránce dokumentace.
Kolace databází
EF Core 5.0 zavádí podporu pro zadávání kolací textu na úrovni databáze, sloupce nebo dotazu. To umožňuje konfigurovat citlivost písmen a další textové aspekty způsobem, který je flexibilní a neohrožuje výkon dotazů.
Následující příklad nakonfiguruje Name
sloupec tak, aby se na SQL Serveru rozlišoval malá a velká písmena a všechny indexy vytvořené ve sloupci budou fungovat odpovídajícím způsobem:
modelBuilder
.Entity<User>()
.Property(e => e.Name)
.UseCollation("SQL_Latin1_General_CP1_CS_AS");
Další informace najdete v úplné dokumentaci ke kolaci a citlivosti velkých a malých písmen.
Čítače událostí
EF Core 5.0 zveřejňuje čítače událostí, které je možné použít ke sledování výkonu vaší aplikace a zjišťování různých anomálií. Jednoduše se připojte k procesu, na kterém běží EF, pomocí nástroje dotnet-counters :
> dotnet counters monitor Microsoft.EntityFrameworkCore -p 49496
[Microsoft.EntityFrameworkCore]
Active DbContexts 1
Execution Strategy Operation Failures (Count / 1 sec) 0
Execution Strategy Operation Failures (Total) 0
Optimistic Concurrency Failures (Count / 1 sec) 0
Optimistic Concurrency Failures (Total) 0
Queries (Count / 1 sec) 1,755
Queries (Total) 98,402
Query Cache Hit Rate (%) 100
SaveChanges (Count / 1 sec) 0
SaveChanges (Total) 1
Další informace najdete v úplné dokumentaci k čítačům událostí.
Další funkce
Vytváření modelů
- Rozhraní API pro vytváření modelů byla zavedena pro snadnější konfiguraci porovnávačů hodnot.
- Počítané sloupce se teď dají nakonfigurovat jako uložené nebo virtuální.
- Přesnost a škálování je teď možné nakonfigurovat prostřednictvím rozhraní Fluent API.
- Nová rozhraní API pro vytváření modelů byla zavedena pro navigační vlastnosti.
- Nová rozhraní API pro vytváření modelů byla zavedena pro pole podobná vlastnostem.
- Typy .NET PhysicalAddress a IPAddress se teď dají mapovat na sloupce řetězců databáze.
- Backing field je teď možné nakonfigurovat prostřednictvím nového
[BackingField]
atributu. - Backingová pole s možnou hodnotou null jsou teď povolená a poskytují lepší podporu výchozích hodnot generovaných úložištěm, kde výchozí hodnota CLR není dobrou hodnotou sentinelu (je to velmi dobré
bool
). - Nový
[Index]
atribut lze použít u typu entity k určení indexu místo použití rozhraní Fluent API. - Nový
[Keyless]
atribut lze použít ke konfiguraci typu entity jako bez klíče. - EF Core ve výchozím nastavení považuje za úplné diskriminátory, což znamená, že očekává, že nikdy neuvidí diskriminující hodnoty, které aplikace nenakonfigurovala v modelu. To umožňuje určitá vylepšení výkonu a může být zakázána, pokud váš nediskriminační sloupec může obsahovat neznámé hodnoty.
Dotaz
- Výjimky selhání překladu dotazů teď obsahují explicitnější důvody příčin selhání, které vám pomůžou problém určit.
- Dotazy bez sledování teď můžou provádět překlad identit a vyhnout se vrácení více instancí entit pro stejný databázový objekt.
- Přidání podpory pro GroupBy s podmíněnými agregacemi (např.
GroupBy(o => o.OrderDate).Select(g => g.Count(i => i.OrderDate != null))
). - Byla přidána podpora pro překlad operátoru Distinct nad prvky skupiny před agregací.
- Překlad .
Reverse
- Vylepšený překlad
DateTime
pro SQL Server (např.DateDiffWeek
DateFromParts
- Překlad nových metod pro bajtová pole (např.
Contains
,Length
,SequenceEqual
). - Překlad některých dalších bitových operátorů, jako je doplněk dvou.
- Překlad řetězců
FirstOrDefault
- Vylepšené překlady dotazů kolem sémantiky null, což vede k přísnějším a efektivnějším dotazům.
- Uživatelem mapované funkce teď můžou být opatřeny poznámkami k řízení šíření hodnoty null, což opět vede k přísnějším a efektivnějším dotazům.
- Sql obsahující bloky CASE je teď výrazně stručnější.
- Funkci SQL Serveru
DATALENGTH
je teď možné volat v dotazech pomocí novéEF.Functions.DataLength
metody. EnableDetailedErrors
přidá další podrobnosti k výjimkám.
Zachraňování
- SaveChanges interception and events.
- Rozhraní API byla zavedena pro řízení bodů ukládání transakcí. Ef Core navíc automaticky vytvoří bod uložení, když
SaveChanges
je volána a transakce už probíhá, a v případě selhání se k němu vrátí zpět. - ID transakce může aplikace explicitně nastavit, což umožňuje snadnější korelaci událostí transakcí v protokolování a jinde.
- Výchozí maximální velikost dávky pro SQL Server byla změněna na 42 na základě analýzy výkonu dávkování.
Migrace a generování uživatelského rozhraní
- Tabulky se teď dají vyloučit z migrací.
- Nový
dotnet ef migrations list
příkaz teď ukazuje, které migrace ještě nebyly použity pro databázi (Get-Migration
dělá to stejné v konzole pro správu balíčků). - Skripty migrace teď obsahují příkazy transakcí tam, kde je to vhodné, aby se zlepšily případy zpracování, kdy aplikace migrace selže.
- Sloupce pro nemapované základní třídy jsou teď seřazené za ostatními sloupci pro mapované typy entit. Všimněte si, že se to týká pouze nově vytvořených tabulek; pořadí sloupců pro existující tabulky zůstává beze změny.
- Generování migrace teď může vědět, jestli je vygenerovaná migrace idempotentní a jestli se výstup spustí okamžitě nebo vygeneruje jako skript.
- Byly přidány nové parametry příkazového řádku pro zadání oborů názvů v migracích a generování uživatelského rozhraní.
- Příkaz dotnet ef database update teď přijímá nový
--connection
parametr pro zadání připojovací řetězec. - Generování existujících databází teď vygeneruje názvy tabulek, takže tabulky pojmenované
People
aAddresses
budou vygenerovány na typy entit, které volanéPerson
aAddress
. Původní názvy databází je stále možné zachovat. - Nová
--no-onconfiguring
možnost může instruovat EF Core, aby při generování modelu vyloučilaOnConfiguring
.
Azure Cosmos DB
- Nastavení připojení ke službě Azure Cosmos DB bylo rozšířeno.
- Optimistická souběžnost se teď podporuje ve službě Azure Cosmos DB prostřednictvím značek ETag.
- Nová
WithPartitionKey
metoda umožňuje, aby klíč oddílu služby Azure Cosmos DB byl zahrnut do modelu i do dotazů. - Řetězcové metody
Contains
StartsWith
aEndsWith
nyní se překládají pro službu Azure Cosmos DB. - Operátor jazyka C#
is
je teď přeložený ve službě Azure Cosmos DB.
Sqlite
- Počítané sloupce jsou teď podporované.
- Načítání binárních a řetězcových dat pomocí GetBytes, GetChars a GetTextReader je nyní efektivnější díky použití SqliteBlob a streamů.
- Inicializace sqliteConnection je teď opožděná.
Jiný důvod
- Proxy servery pro sledování změn lze generovat, které automaticky implementují INotifyPropertyChanging a INotifyPropertyChanged. To poskytuje alternativní přístup ke sledování změn, který neskenuje změny při
SaveChanges
zavolání. - U DbConnection již inicializovaného dbContextu je teď možné změnit nebo připojovací řetězec.
- Nová ChangeTracker.Clear metoda vymaže DbContext všech sledovaných entit. To by obvykle nemělo být potřeba při použití osvědčeného postupu při vytváření nové krátkodobé instance kontextu pro každou jednotku práce. Pokud ale potřebujete resetovat stav instance DbContext, je použití nové
Clear()
metody efektivnější a robustnější než hromadné odpojení všech entit. - Nástroje příkazového řádku EF Core teď automaticky konfigurují
ASPNETCORE_ENVIRONMENT
proměnné prostředíDOTNET_ENVIRONMENT
na Vývoj. To přináší prostředí při použití obecného hostitele v souladu s prostředím pro ASP.NET Core během vývoje. - Do vlastních argumentů příkazového řádku lze tokovat IDesignTimeDbContextFactory<TContext>, což umožňuje aplikacím řídit, jak se kontext vytváří a inicializuje.
- Faktor vyplnění indexu je teď možné nakonfigurovat na SQL Serveru.
- Novou IsRelational vlastnost lze použít k rozlišení při použití relačního zprostředkovatele a jiného než relačního zprostředkovatele (například v paměti).