Upgrade aplikací z předchozích verzí na EF Core 2.0

Využili jsme příležitost výrazně upřesnit naše stávající rozhraní API a chování ve verzi 2.0. Existuje několik vylepšení, která mohou vyžadovat úpravu existujícího kódu aplikace, i když se domníváme, že u většiny aplikací bude dopad nízký, ve většině případů vyžaduje pouze rekompilace a minimální řízené změny nahrazení zastaralých rozhraní API.

Aktualizace existující aplikace na EF Core 2.0 může vyžadovat:

  1. Upgrade cílové implementace .NET aplikace na aplikaci, která podporuje .NET Standard 2.0. Další podrobnosti najdete v tématu Podporované implementace .NET.

  2. Identifikujte zprostředkovatele cílové databáze, která je kompatibilní s EF Core 2.0. Viz EF Core 2.0 vyžaduje níže zprostředkovatele databáze 2.0.

  3. Upgradujte všechny balíčky EF Core (modul runtime a nástroje) na verzi 2.0. Další podrobnosti najdete v tématu Instalace EF Core .

  4. Proveďte všechny nezbytné změny kódu, které kompenzují zásadní změny popsané ve zbývající části tohoto dokumentu.

ASP.NET Core teď zahrnuje EF Core.

Aplikace cílené na ASP.NET Core 2.0 můžou používat EF Core 2.0 bez dalších závislostí kromě poskytovatelů databází třetích stran. Aplikace, které cílí na předchozí verze ASP.NET Core, ale musí upgradovat na ASP.NET Core 2.0, aby mohly používat EF Core 2.0. Další podrobnosti o upgradu aplikací ASP.NET Core na verzi 2.0 najdete v dokumentaci ASP.NET Core k tomuto tématu.

Nový způsob získávání aplikačních služeb v ASP.NET Core

Doporučený vzor pro webové aplikace ASP.NET Core byl aktualizován na verzi 2.0 způsobem, který přerušil logiku návrhu EF Core používanou v 1.x. Ef Core se dříve v době návrhu pokusil vyvolat Startup.ConfigureServices přímo za účelem přístupu k poskytovateli služeb aplikace. V ASP.NET Core 2.0 se konfigurace inicializuje mimo Startup třídu. Aplikace používající EF Core obvykle přistupují ke svým připojovací řetězec z konfigurace, takže Startup sama o sobě už nestačí. Pokud upgradujete aplikaci ASP.NET Core 1.x, při použití nástrojů EF Core se může zobrazit následující chyba.

V applicationContext nebyl nalezen žádný konstruktor bez parametrů. Buď přidejte konstruktor bez parametrů do ApplicationContext, nebo přidejte implementaci IDesignTimeDbContextFactory<ApplicationContext> ve stejném sestavení jako ApplicationContext.

Do výchozí šablony ASP.NET Core 2.0 jsme přidali nový háček pro návrh. Statická Program.BuildWebHost metoda umožňuje EF Core přistupovat k poskytovateli služeb aplikace v době návrhu. Pokud upgradujete aplikaci ASP.NET Core 1.x, budete muset aktualizovat Program třídu tak, aby připomínala následující.

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace AspNetCoreDotNetCore2._0App
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}

Přijetí tohoto nového modelu při aktualizaci aplikací na verzi 2.0 se důrazně doporučuje a vyžaduje se, aby funkce produktů, jako jsou migrace Entity Framework Core, fungovaly. Další běžnou alternativou je implementace IDesignTimeDbContextFactory<TContext>.

Přejmenování IDbContextFactory

Abychom podpořili různé vzory aplikací a poskytli uživatelům větší kontrolu nad tím, jak se používají DbContext v době návrhu IDbContextFactory<TContext> , poskytujeme rozhraní v minulosti. Nástroje EF Core v době návrhu zjistí implementace tohoto rozhraní v projektu a použijí ho k vytváření DbContext objektů.

Toto rozhraní mělo velmi obecný název, který některé uživatele omylem pokusil znovu použít pro jiné DbContextscénáře vytváření. Byli zachyceni, když se nástroje EF pak pokusily použít jejich implementaci v době návrhu a způsobily příkazy jako Update-Database nebo dotnet ef database update selhání.

Abychom mohli komunikovat silnou sémantiku návrhu tohoto rozhraní, přejmenovali jsme jej na IDesignTimeDbContextFactory<TContext>.

Pro vydání IDbContextFactory<TContext> verze 2.0 stále existuje, ale je označen jako zastaralé.

Odebrání dbContextFactoryOptions

Z důvodu výše popsaných změn ASP.NET Core 2.0 jsme zjistili, že DbContextFactoryOptions v novém IDesignTimeDbContextFactory<TContext> rozhraní už nebylo potřeba. Tady jsou alternativy, které byste měli místo toho použít.

DbContextFactoryOptions Alternativa
ApplicationBasePath AppContext.BaseDirectory
ContentRootPath Directory.GetCurrentDirectory()
EnvironmentName Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")

Změnil se pracovní adresář v době návrhu

Změny ASP.NET Core 2.0 také vyžadovaly dotnet ef pracovní adresář používaný v souladu s pracovním adresářem používaným sadou Visual Studio při spuštění aplikace. Jedním z pozorovatelných vedlejších účinků je, že názvy souborů SQLite jsou teď relativní vzhledem k adresáři projektu, a ne výstupnímu adresáři, jako by se používaly.

EF Core 2.0 vyžaduje poskytovatele databáze 2.0.

Pro EF Core 2.0 jsme provedli mnoho zjednodušení a vylepšení způsobu, jakým poskytovatelé databází pracují. To znamená, že poskytovatelé 1.0.x a 1.1.x nebudou s EF Core 2.0 fungovat.

Poskytovatelé SQL Serveru a SQLite jsou dodávány týmem EF a verzemi 2.0 budou k dispozici jako součást verze 2.0. Poskytovatelé open source třetích stran pro SQL Compact, PostgreSQL a MySQL se aktualizují na verzi 2.0. U všech ostatních poskytovatelů se obraťte na autora poskytovatele.

Protokolování a diagnostické události se změnily.

Poznámka: Tyto změny by neměly mít vliv na většinu kódu aplikace.

ID událostí pro zprávy odeslané do ILoggeru se změnily ve verzi 2.0. ID událostí jsou nyní napříč kódem EF Core jedinečná. Tyto zprávy se nyní také řídí standardním vzorem pro strukturované protokolování, který používá například MVC.

Změnily se také kategorie protokolovacího nástroje. Nyní existuje dobře známá sada kategorií, ke které se přistupuje prostřednictvím DbLoggerCategory.

DiagnosticSource události teď používají stejné názvy ID události jako odpovídající ILogger zprávy. Datové části událostí jsou všechny nominální typy odvozené z EventData.

ID událostí, typy datových částí a kategorie jsou zdokumentované v CoreEventId a relačníchEventId třídách.

ID se také přesunula z Microsoft.EntityFrameworkCore.Infrastructure do nového oboru názvů Microsoft.EntityFrameworkCore.Diagnostics.

Změny rozhraní API relačních metadat EF Core

EF Core 2.0 nyní pro každého použitého zprostředkovatele vytvoří jiný IModel. To je pro aplikaci obvykle transparentní. To usnadnilo zjednodušení rozhraní API pro metadata nižší úrovně tak, aby jakýkoli přístup k běžným konceptům relačních metadat byl vždy proveden voláním .Relational namísto .SqlServer, .Sqliteatd. Například kód 1.1.x takto:

var tableName = context.Model.FindEntityType(typeof(User)).SqlServer().TableName;

Teď by se mělo napsat takto:

var tableName = context.Model.FindEntityType(typeof(User)).Relational().TableName;

Místo použití metod, jako ForSqlServerToTablejsou , jsou teď metody rozšíření k dispozici pro zápis podmíněného kódu na základě aktuálního poskytovatele, který se používá. Příklad:

modelBuilder.Entity<User>().ToTable(
    Database.IsSqlServer() ? "SqlServerName" : "OtherName");

Upozorňujeme, že tato změna se vztahuje pouze na rozhraní API a metadata definovaná pro všechny relační zprostředkovatele. Rozhraní API a metadata zůstávají stejné, pokud je specifické jenom pro jednoho zprostředkovatele. Například clusterované indexy jsou specifické pro SQL Server, takže ForSqlServerIsClustered je .SqlServer().IsClustered() nutné je stále používat.

Nepřebíjejte kontrolu nad poskytovatelem služeb EF

EF Core pro interní implementaci používá interní IServiceProvider (kontejner injektáže závislostí). Aplikace by měly umožnit ef Core vytvářet a spravovat tohoto poskytovatele s výjimkou zvláštních případů. Důrazně zvažte odebrání všech volání .UseInternalServiceProvider Pokud aplikace potřebuje volat UseInternalServiceProvider, zvažte vytvoření problému , abychom mohli prozkoumat další způsoby zpracování vašeho scénáře.

Volání AddEntityFramework, AddEntityFrameworkSqlServeratd. není vyžadováno kódem aplikace, pokud UseInternalServiceProvider není volána také. Odeberte všechna existující volání nebo AddEntityFrameworkAddEntityFrameworkSqlServeratd. AddDbContext by se měla používat stejným způsobem jako předtím.

Databáze v paměti musí mít název

Globální nepojmenovaná databáze v paměti byla odebrána a místo toho musí být pojmenovány všechny databáze v paměti. Příklad:

optionsBuilder.UseInMemoryDatabase("MyDatabase");

Tím se vytvoří nebo použije databáze s názvem "MyDatabase". Pokud UseInMemoryDatabase se znovu zavolá se stejným názvem, použije se stejná databáze v paměti, která umožňuje sdílení více kontextových instancí.

Operace Zahrnutí zprostředkovatele v paměti už nevrací výsledky, pokud je zahrnutá navigace požadovaná, ale její hodnota je null

Při pokusu o zahrnutí požadované navigace a zahrnutá navigace má hodnotu null, dotaz už nevrací výsledek entity, na které je použita operace Include. Chcete-li se tomuto problému vyhnout, zadejte hodnotu požadované navigace nebo změňte navigaci tak, aby byla volitelná.

public class Person
{
    public int Id { get; set; }
    public Language NativeLanguage { get; set;} // required navigation
    public Person Sibling { get; set; } // optional navigation
}
...
var person = new Person();
context.People.Add(person);
context.SaveChanges();
...

// returns one result
context.People.ToList();

// returns no results because 'NativeLanguage' navigation is required but has not been provided
context.People.Include(p => p.NativeLanguage).ToList(); 

// returns one result because 'Sibling' navigation is optional so it doesn't have to be provided
context.People.Include(p => p.Sibling).ToList(); 

Změny rozhraní API jen pro čtení

IsReadOnlyBeforeSave, IsReadOnlyAfterSavea byly zastaralé a IsStoreGeneratedAlways nahrazeny beforeSaveBehavior a AfterSaveBehavior. Toto chování platí pro libovolnou vlastnost (nejen vlastnosti generované úložištěm) a určuje, jak se má hodnota vlastnosti použít při vkládání do řádku databáze (BeforeSaveBehavior) nebo při aktualizaci existujícího řádku databáze (AfterSaveBehavior).

Vlastnosti označené jako ValueGenerated.OnAddOrUpdate (například pro počítané sloupce) budou ve výchozím nastavení ignorovat jakoukoli hodnotu, která je aktuálně nastavena pro vlastnost. To znamená, že se vždy získá vygenerovaná hodnota úložiště bez ohledu na to, jestli byla u sledované entity nastavena nebo upravena nějaká hodnota. To lze změnit nastavením jiné Before\AfterSaveBehavior.

Nové chování odstranění ClientSetNull

V předchozích verzích měla DeleteBehavior.Restrict chování entit sledovaných kontextem, který se více zavřel sémantikou SetNull . V EF Core 2.0 ClientSetNull se nové chování zavedlo jako výchozí pro volitelné relace. Toto chování má SetNull sémantiku pro sledované entity a Restrict chování databází vytvořených pomocí EF Core. V našem prostředí se jedná o nejočekálejší/užitečné chování sledovaných entit a databáze. DeleteBehavior.Restrict u sledovaných entit je nyní dodržen při nastavení volitelných relací.

Odebrané balíčky pro návrh zprostředkovatele

Balíček Microsoft.EntityFrameworkCore.Relational.Design byl odebrán. Obsah byl sloučen do Microsoft.EntityFrameworkCore.Relational a Microsoft.EntityFrameworkCore.Design.

To se rozšíří do balíčků návrhu poskytovatele. Tyto balíčky (Microsoft.EntityFrameworkCore.Sqlite.Designatd Microsoft.EntityFrameworkCore.SqlServer.Design.) byly odebrány a jejich obsah konsolidovaný do hlavních balíčků zprostředkovatelů.

Pokud chcete povolit Scaffold-DbContext nebo dotnet ef dbcontext scaffold použít EF Core 2.0, stačí odkazovat jenom na jeden balíček zprostředkovatele:

<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer"
    Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools"
    Version="2.0.0"
    PrivateAssets="All" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet"
    Version="2.0.0" />