Sdílet prostřednictvím


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ř. DateDiffWeekDateFromParts
  • 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 a Addresses budou vygenerovány na typy entit, které volané Person a Address. 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čila OnConfiguring .

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).