Generování uživatelského rozhraní (zpětná analýza)
Zpětná analýza je proces generování tříd typů entit a třídy DbContext založené na schématu databáze. Analýza se provádí příkazem Scaffold-DbContext
v nástrojích PMC (Package Manager Console) mapovače EF Core nebo příkazem dotnet ef dbcontext scaffold
v nástrojích CLI (rozhraní příkazového řádku).
Poznámka:
Generování DbContext
typů entit a typů entit zdokumentovaných zde se liší od generování řadičů v ASP.NET Core pomocí sady Visual Studio, které zde není zdokumentované.
Tip
Pokud používáte Visual Studio, vyzkoušejte komunitní rozšíření EF Core Power Tools . Tyto nástroje poskytují grafický nástroj, který je založen na nástrojích příkazového řádku EF Core a nabízí další možnosti pracovního postupu a přizpůsobení.
Požadavky
- Před generováním uživatelského rozhraní budete muset nainstalovat buď nástroje PMC, které fungují jenom v sadě Visual Studio, nebo nástroje .NET CLI, které jsou na všech platformách podporovaných rozhraním .NET.
- Balíček NuGet pro
Microsoft.EntityFrameworkCore.Design
nainstalujte do projektu, do kterého chcete třídy generovat. - Nainstalujte balíček NuGet pro zprostředkovatele databáze, který cílí na schéma databáze, ze kterého chcete vygenerovat generování.
Požadované argumenty
Příkazy PMC i .NET CLI mají dva povinné argumenty: připojovací řetězec k databázi a zprostředkovatele databáze EF Core, který se má použít.
Connection string
Upozorňující
Tento článek používá místní databázi, která nevyžaduje ověření uživatele. Produkční aplikace by měly používat nejbezpečnější dostupný tok ověřování. Další informace o ověřování nasazených testovacích a produkčníchaplikacích
Prvním argumentem příkazu je připojovací řetězec databáze. Nástroje používají tento připojovací řetězec ke čtení schématu databáze.
Způsob, jakým je připojovací řetězec uvozován a uvozován, závisí na prostředí, které se používá ke spuštění příkazu. Projděte si dokumentaci k prostředí. PowerShell například vyžaduje zapouzdření $
, ale ne \
.
Následující příklad vygeneruje typy entit a z DbContext
Chinook
databáze umístěné v instanci SQL Server LocalDB počítače, která využívá Microsoft.EntityFrameworkCore.SqlServer
zprostředkovatele databáze.
dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
Tip
Konfiguraci můžete použít k uložení a načtení připojovací řetězec
Připojovací řetězce v kódu vygenerovaného uživatelského rozhraní
Ve výchozím nastavení bude vygenerovaný kód obsahovat připojovací řetězec, ale s upozorněním. Příklad:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#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.UseSqlServer("Data Source=(LocalDb)\\MSSQLLocalDB;Database=AllTogetherNow");
To se provádí tak, aby se vygenerovaný kód při prvním použití nehroutí, což by bylo velmi špatné zkušenosti s učením. Jak ale uvádí upozornění, připojovací řetězec by v produkčním kódu neměly existovat. Různé způsoby, jak je možné spravovat připojovací řetězec, najdete v tématu Životnost, Konfigurace a Inicializace DbContext.
Tip
Možnost -NoOnConfiguring
(Visual Studio PMC) nebo --no-onconfiguring
(.NET CLI) lze předat, aby se potlačí vytvoření OnConfiguring
metody obsahující připojovací řetězec.
Název poskytovatele
Druhým argumentem je název poskytovatele. Název poskytovatele je obvykle stejný jako název poskytovatele balíčku NuGet. Například pro SQL Server nebo Azure SQL použijte Microsoft.EntityFrameworkCore.SqlServer
.
Možnosti příkazového řádku
Proces generování uživatelského rozhraní je možné řídit různými možnostmi příkazového řádku.
Určení tabulek a zobrazení
Ve výchozím nastavení se všechny tabulky a zobrazení ve schématu databáze vygenerují do typů entit. Počet vygenerovaných tabulek a zobrazení můžete omezit zadáním schémat a tabulek.
Argument -Schemas
(PMC) nebo --schema
(.NET CLI) (Visual Studio PMC) určuje schémata tabulek a zobrazení, pro které typy entit budou generovány. Pokud tento argument vynecháte, budou zahrnuta všechna schémata. Pokud použijete tuto možnost, budou všechny tabulky a zobrazení ve schématech zahrnuty do modelu, i když nejsou explicitně zahrnuty pomocí -Tables
nebo --table
.
Argument -Tables
(PMC) nebo --table
(.NET CLI) (Visual Studio PMC) zadal tabulky a zobrazení, pro které se budou generovat typy entit. Tabulky nebo zobrazení v určitém schématu lze zahrnout pomocí formátu schema.table nebo schema.view. Pokud tuto možnost vynecháte, budou zahrnuty všechny tabulky a zobrazení. |
Pokud například chcete vygenerovat jenom tabulky Artists
a Albums
tabulky:
dotnet ef dbcontext scaffold ... --table Artist --table Album
Generování všech tabulek a zobrazení ze Customer
schémat a Contractor
schémat:
dotnet ef dbcontext scaffold ... --schema Customer --schema Contractor
Například pro generování Purchases
tabulky ze schématu Customer
a Accounts
Contracts
tabulek ze schématu Contractor
:
dotnet ef dbcontext scaffold ... --table Customer.Purchases --table Contractor.Accounts --table Contractor.Contracts
Zachování názvů databází
Názvy tabulek a sloupců se automaticky opraví, aby lépe odpovídaly zásadám vytváření názvů typů a vlastností. Pokud -UseDatabaseNames
zadáte (Visual Studio PMC) nebo --use-database-names
(.NET CLI), toto chování zakážete, aby se zachovaly původní názvy databází co nejvíce. I přesto se opraví neplatné identifikátory .NET a syntetizované názvy, například navigační vlastnosti, aby vyhovovaly zásadám vytváření názvů v .NET.
Představte si například následující tabulky:
CREATE TABLE [BLOGS] (
[ID] int NOT NULL IDENTITY,
[Blog_Name] nvarchar(max) NOT NULL,
CONSTRAINT [PK_Blogs] PRIMARY KEY ([ID]));
CREATE TABLE [posts] (
[id] int NOT NULL IDENTITY,
[postTitle] nvarchar(max) NOT NULL,
[post content] nvarchar(max) NOT NULL,
[1 PublishedON] datetime2 NOT NULL,
[2 DeletedON] datetime2 NULL,
[BlogID] int NOT NULL,
CONSTRAINT [PK_Posts] PRIMARY KEY ([id]),
CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogID]) REFERENCES [Blogs] ([ID]) ON DELETE CASCADE);
Ve výchozím nastavení se z těchto tabulek vygenerují následující typy entit:
public partial class Blog
{
public int Id { get; set; }
public string BlogName { get; set; } = null!;
public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
}
public partial class Post
{
public int Id { get; set; }
public string PostTitle { get; set; } = null!;
public string PostContent { get; set; } = null!;
public DateTime _1PublishedOn { get; set; }
public DateTime? _2DeletedOn { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; } = null!;
public virtual ICollection<Tag> Tags { get; set; } = new List<Tag>();
}
Použití -UseDatabaseNames
nebo --use-database-names
výsledky však mají následující typy entit:
public partial class BLOG
{
public int ID { get; set; }
public string Blog_Name { get; set; } = null!;
public virtual ICollection<post> posts { get; set; } = new List<post>();
}
public partial class post
{
public int id { get; set; }
public string postTitle { get; set; } = null!;
public string post_content { get; set; } = null!;
public DateTime _1_PublishedON { get; set; }
public DateTime? _2_DeletedON { get; set; }
public int BlogID { get; set; }
public virtual BLOG Blog { get; set; } = null!;
}
Použití atributů mapování (neboli datových poznámek)
Typy entit se ve výchozím nastavení konfigurují pomocí rozhraní APIOnModelCreating
.ModelBuilder
Pokud je to možné, zadejte -DataAnnotations
(PMC) nebo --data-annotations
(.NET Core CLI), aby místo toho používaly atributy mapování.
Při použití Fluent API se vygeneruje například toto:
entity.Property(e => e.Title)
.IsRequired()
.HasMaxLength(160);
Ale při použití datových poznámek se vygeneruje toto:
[Required]
[StringLength(160)]
public string Title { get; set; }
Tip
Některé aspekty modelu nelze nakonfigurovat pomocí atributů mapování. Scaffolder bude stále používat rozhraní API pro vytváření modelů ke zpracování těchto případů.
Název DbContext
Název vygenerované DbContext
třídy bude ve výchozím nastavení název databáze s příponou Context . Pokud chcete zadat jiný název, použijte v PMC možnost -Context
a v rozhraní příkazového řádku .NET Core použijte --context
.
Cílové adresáře a obory názvů
Třídy entit a třída DbContext se vygenerují do kořenového adresáře projektu s použitím výchozího oboru názvů projektu.
Pokud chcete zadat adresář, do kterého se budou třídy generovat, použijte --output-dir
. Pokud chcete generovat třídu DbContext do adresáře odděleného od tříd typů entit, použijte --context-dir
:
dotnet ef dbcontext scaffold ... --context-dir Data --output-dir Models
Jako obor názvů se automaticky použije kořenový obor názvů plus názvy podadresářů v kořenovém adresáři projektu. Obor názvů pro všechny výstupní třídy však můžete přepsat pomocí .--namespace
K přepsání oboru názvů jen u třídy DbContext také můžete použít --context-namespace
:
dotnet ef dbcontext scaffold ... --namespace Your.Namespace --context-namespace Your.DbContext.Namespace
Vygenerovaný kód
Výsledkem generování uživatelského rozhraní z existující databáze je:
- Soubor obsahující třídu, která dědí z
DbContext
- Soubor pro každý typ entity
Tip
Od verze EF7 také můžete k přizpůsobení generovaného kódu používat šablony textu T4. Podrobnější informace najdete v šablonách vlastní zpětné analýzy.
Referenční typy C# s možnou hodnotou Null
Scaffolder může vytvořit model EF a typy entit, které používají odkazové typy C# s možnou hodnotou null (NRT). Použití NRT se automaticky vygeneruje, když je v projektu C# povolená podpora NRT, do kterého se kód vygeneruje.
Například následující Tags
tabulka obsahuje oba sloupce řetězců s možnou hodnotou null:
CREATE TABLE [Tags] (
[Id] int NOT NULL IDENTITY,
[Name] nvarchar(max) NOT NULL,
[Description] nvarchar(max) NULL,
CONSTRAINT [PK_Tags] PRIMARY KEY ([Id]));
Výsledkem jsou odpovídající vlastnosti řetězce s možnou hodnotou null a nenulovou hodnotou ve vygenerované třídě:
public partial class Tag
{
public Tag()
{
Posts = new HashSet<Post>();
}
public int Id { get; set; }
public string Name { get; set; } = null!;
public string? Description { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
Podobně následující Posts
tabulky obsahují požadovanou relaci s Blogs
tabulkou:
CREATE TABLE [Posts] (
[Id] int NOT NULL IDENTITY,
[Title] nvarchar(max) NOT NULL,
[Contents] nvarchar(max) NOT NULL,
[PostedOn] datetime2 NOT NULL,
[UpdatedOn] datetime2 NULL,
[BlogId] int NOT NULL,
CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]));
Výsledkem je generování relace bez hodnoty null (povinné) mezi blogy:
public partial class Blog
{
public Blog()
{
Posts = new HashSet<Post>();
}
public int Id { get; set; }
public string Name { get; set; } = null!;
public virtual ICollection<Post> Posts { get; set; }
}
A příspěvky:
public partial class Post
{
public Post()
{
Tags = new HashSet<Tag>();
}
public int Id { get; set; }
public string Title { get; set; } = null!;
public string Contents { get; set; } = null!;
public DateTime PostedOn { get; set; }
public DateTime? UpdatedOn { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; } = null!;
public virtual ICollection<Tag> Tags { get; set; }
}
Relace M:N
Proces generování uživatelského rozhraní rozpozná jednoduché tabulky spojení a automaticky pro ně vygeneruje mapování M:N. Zvažte například tabulky pro Posts
tabulky a Tags
spojovací tabulku PostTag
, která je propojí:
CREATE TABLE [Tags] (
[Id] int NOT NULL IDENTITY,
[Name] nvarchar(max) NOT NULL,
[Description] nvarchar(max) NULL,
CONSTRAINT [PK_Tags] PRIMARY KEY ([Id]));
CREATE TABLE [Posts] (
[Id] int NOT NULL IDENTITY,
[Title] nvarchar(max) NOT NULL,
[Contents] nvarchar(max) NOT NULL,
[PostedOn] datetime2 NOT NULL,
[UpdatedOn] datetime2 NULL,
CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]));
CREATE TABLE [PostTag] (
[PostsId] int NOT NULL,
[TagsId] int NOT NULL,
CONSTRAINT [PK_PostTag] PRIMARY KEY ([PostsId], [TagsId]),
CONSTRAINT [FK_PostTag_Posts_TagsId] FOREIGN KEY ([TagsId]) REFERENCES [Tags] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_PostTag_Tags_PostsId] FOREIGN KEY ([PostsId]) REFERENCES [Posts] ([Id]) ON DELETE CASCADE);
Když se vygeneruje, výsledkem bude třída Post:
public partial class Post
{
public Post()
{
Tags = new HashSet<Tag>();
}
public int Id { get; set; }
public string Title { get; set; } = null!;
public string Contents { get; set; } = null!;
public DateTime PostedOn { get; set; }
public DateTime? UpdatedOn { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; } = null!;
public virtual ICollection<Tag> Tags { get; set; }
}
A třída pro Tag:
public partial class Tag
{
public Tag()
{
Posts = new HashSet<Post>();
}
public int Id { get; set; }
public string Name { get; set; } = null!;
public string? Description { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
Ale žádná třída tabulky PostTag
. Místo toho se konfigurace relace M:N vygeneruje:
entity.HasMany(d => d.Tags)
.WithMany(p => p.Posts)
.UsingEntity<Dictionary<string, object>>(
"PostTag",
l => l.HasOne<Tag>().WithMany().HasForeignKey("PostsId"),
r => r.HasOne<Post>().WithMany().HasForeignKey("TagsId"),
j =>
{
j.HasKey("PostsId", "TagsId");
j.ToTable("PostTag");
j.HasIndex(new[] { "TagsId" }, "IX_PostTag_TagsId");
});
Další programovací jazyky
Balíčky EF Core publikované kódem C# uživatelského rozhraní Microsoftu. Základní systém generování uživatelského rozhraní však podporuje model modulu plug-in pro generování v jiných jazycích. Tento model modulu plug-in používá různé projekty spuštěné komunitou, například:
- EntityFrameworkCore.VisualBasic poskytuje podporu pro Visual Basic
- EFCore.FSharp poskytuje podporu pro F#
Přizpůsobení kódu
Od EF7 je jedním z nejlepších způsobů přizpůsobení vygenerovaného kódu přizpůsobením šablon T4 použitých k jeho vygenerování.
Kód lze také po vygenerování změnit, ale nejlepší způsob, jak to udělat, závisí na tom, jestli chcete znovu spustit proces generování při změně modelu databáze.
Generování uživatelského rozhraní pouze jednou
Díky tomuto přístupu poskytuje kód vygenerovaný vygenerovaný kód výchozí bod pro mapování založené na kódu. Všechny změny vygenerovaného kódu je možné provést podle potřeby – stane se normálním kódem stejně jako jakýkoli jiný kód v projektu.
Synchronizaci databáze a modelu EF je možné provádět jedním ze dvou způsobů:
- Přepněte na migraci databází EF Core a jako zdroj pravdivých dat použijte typy entit a konfiguraci modelu EF. K řízení schématu použijte migrace.
- Při změně databáze ručně aktualizujte typy entit a konfiguraci EF. Pokud je například do tabulky přidán nový sloupec, přidejte vlastnost sloupce k mapovanému typu entity a přidejte jakoukoli potřebnou konfiguraci pomocí atributů mapování a/nebo kódu v
OnModelCreating
souboru . To je poměrně snadné, protože jediným skutečným problémem je proces, který zajistí, aby se změny databáze zaznamenávaly nebo detekovaly nějakým způsobem, aby vývojáři zodpovědní za kód mohli reagovat.
Opakované generování uživatelského rozhraní
Alternativním přístupem k vygenerování jednou je opětovné generování při každé změně databáze. Tím se přepíše veškerý dříve vygenerovaný kód, což znamená, že všechny změny typů entit nebo konfigurace EF v tomto kódu budou ztraceny.
[TIP] Ve výchozím nastavení příkazy EF nepřepíšou žádný existující kód, který bude chránit před náhodnou ztrátou kódu. Argument
-Force
(PMC) nebo--force
.NET CLI (Visual Studio PMC) lze použít k vynucení přepsání existujících souborů.
Vzhledem k tomu, že se vygenerovaný kód přepíše, je nejlepší ho přímo upravit, ale místo toho spoléhat na částečné třídy a metody a mechanismy v EF Core, které umožňují přepsání konfigurace. Konkrétně:
- Třídy
DbContext
i třídy entit se generují jako částečné. To umožňuje zavést další členy a kód do samostatného souboru, který se při spuštění generování nepřepíše. - Třída
DbContext
obsahuje částečnou metodu volanouOnModelCreatingPartial
. Implementace této metody lze přidat do částečné třídy proDbContext
. Potom bude volána poOnModelCreating
zavolání. - Konfigurace modelu vytvořená pomocí
ModelBuilder
rozhraní API přepíše veškerou konfiguraci provedenou konvencemi nebo atributy mapování a také dřívější konfiguraci provedenou v tvůrci modelů. To znamená, že kód vOnModelCreatingPartial
tomto kódu lze použít k přepsání konfigurace vygenerované procesem generování uživatelského rozhraní, aniž by bylo nutné tuto konfiguraci odebrat.
Nezapomeňte, že od EF7 je možné přizpůsobit šablony T4 použité ke generování kódu. To je často efektivnější přístup než generování s výchozími nastaveními a následné úpravy s částečnými třídami nebo metodami.
Jak to funguje
Zpětná analýza začíná čtením databázového schématu. Přečte informace o tabulkách, sloupcích, omezeních a indexech.
V dalším kroku analýza použije informace ze schématu k vytvoření modelu EF Core. Tabulky se použijí k vytvoření typů entit, sloupce se použijí k vytvoření vlastností a cizí klíče se použijí k vytvoření relací.
Nakonec se model použije ke generování kódu. Vygenerují se odpovídající třídy typů entit, rozhraní Fluent API a datové poznámky, aby z aplikace mohl být znovu vytvořen stejný model.
Omezení
- Schéma databáze ale nemůže představovat všechny informace o modelu. Ve schématu databáze například chybí informace o hierarchii dědičnosti, vlastněných typech a dělení tabulek. Z tohoto důvodu se tyto konstrukce nikdy nevygenerují.
- Dále platí, že poskytovatel mapovače EF Core nemusí podporovat některé typy sloupců. Tyto sloupce v modelu nebudou.
- Tokeny souběžnosti můžete definovat v modelu EF Core, aby dva uživatelé nemohli aktualizovat stejnou entitu současně. Některé databáze mají speciální typ, který představuje tento typ sloupce (například rowversion v SQL Serveru), v takovém případě můžeme tyto informace zpětně analyzovat; Jiné tokeny souběžnosti však nebudou vygenerovány.