Sdílet prostřednictvím


Vlastní šablony zpětné analýzy

Poznámka:

Tato funkce byla přidána v EF Core 7.

Při zpětném inženýrstvíse Entity Framework Core snaží vytvořit dobrý, obecně použitelný kód, který lze použít v různých typech aplikací, a používá běžné konvence kódování pro jednotný vzhled a známý pocit. Někdy je však žádoucí specializovanější kód a alternativní styly kódování. Článek ukazuje, jak upravit generovaný kód pomocí T4 textových šablon.

Požadavky

Tento článek předpokládá, že znáte zpětného inženýrství v EF Core. Pokud ne, přečtěte si prosím tento článek, než budete pokračovat.

Přidání výchozích šablon

Prvním krokem k přizpůsobení vygenerovaného kódu je přidání výchozích šablon do projektu. Výchozí šablony jsou ty, které EF Core interně používá při zpětné analýze. Poskytují výchozí bod pro zahájení přizpůsobení základního strukturovaného kódu.

Začněte instalací balíčku šablony EF Core pro dotnet new:

dotnet new install Microsoft.EntityFrameworkCore.Templates

Teď můžete do projektu přidat výchozí šablony. Uděláte to spuštěním následujícího příkazu z adresáře projektu.

dotnet new ef-templates

Tento příkaz přidá do projektu následující soubory.

  • CodeTemplates/
    • EFCore/
      • DbContext.t4
      • EntityType.t4

Šablona DbContext.t4 slouží k generování třídy DbContext pro databázi a šablona EntityType.t4 slouží k generování tříd typů entit pro každou tabulku a zobrazení v databázi.

Návod

Rozšíření .t4 se používá (místo .tt), aby Visual Studio neprovádělo transformaci šablon. Šablony se místo toho transformují pomocí EF Core.

Úvod do T4

Pojďme otevřít šablonu DbContext.t4 a zkontrolovat její obsah. Tento soubor je T4 textová šablona. T4 je jazyk pro generování textu pomocí .NET. Následující kód je určen pouze pro ilustrativní účely; nepředstavuje úplný obsah souboru.

Důležité

Textové šablony T4 – zejména ty, které generují kód – můžou být obtížně čitelné bez zvýrazňování syntaxe. V případě potřeby vyhledejte rozšíření editoru kódu, které umožňuje zvýraznění syntaxe T4.

<#@ template hostSpecific="true" #>
<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #>
<#@ parameter name="NamespaceHint" type="System.String" #>
<#@ import namespace="Microsoft.EntityFrameworkCore" #>
<#
    if (!string.IsNullOrEmpty(NamespaceHint))
    {
#>
namespace <#= NamespaceHint #>;

Prvních pár řádků začínajících <#@ se nazývají direktivy. Ovlivňují způsob transformace šablony. Následující tabulka stručně popisuje každý druh použité direktivy.

Direktiva Popis
template Určuje hostSpecific="true", která umožňuje používat vlastnost Host uvnitř šablony pro přístup ke službám EF Core.
assembly Přidá odkazy na sestavení potřebné ke kompilaci šablony.
parameter Deklaruje parametry, které předá EF Core při transformaci šablony.
import Podobně jako direktivy using v jazyce C# zahrnuje do dosažitelnosti šablonového kódu obory názvů.

Po direktivách se další část DbContext.t4 nazývá řídicí blok. Standardní řídicí blok začíná <# a končí #>. Kód uvnitř se spustí při transformaci šablony. Seznam vlastností a metod dostupných uvnitř řídicích bloků naleznete v TextTransformation třída.

Cokoli mimo řídicí blok se zkopíruje přímo do výstupu šablony.

Blok ovládacího prvku výrazu začíná <#=. Kód uvnitř se vyhodnotí a výsledek se přidá do výstupu šablony. Jsou podobné interpolovaným řetězcovým argumentům jazyka C#.

Podrobnější a úplné vysvětlení syntaxe T4 najdete v tématu Zápis textové šablony T4.

Přizpůsobení typů entit

Pojďme si projít, jak si šablonu přizpůsobit. Ef Core ve výchozím nastavení generuje následující kód pro vlastnosti navigace v kolekci.

public virtual ICollection<Album> Albums { get; } = new List<Album>();

Použití List<T> je pro většinu aplikací dobrým výchozím nastavením. Pokud ale používáte architekturu založenou na XAML, jako je WPF, WinUI nebo .NET MAUI, často chcete k povolení datové vazby použít ObservableCollection<T>.

Otevřete šablonu EntityType.t4 a vyhledejte, kde generuje List<T>. Vypadá takto:

    if (navigation.IsCollection)
    {
#>
    public virtual ICollection<<#= targetType #>> <#= navigation.Name #> { get; } = new List<<#= targetType #>>();
<#
    }

Nahradit List za ObservableCollection.

public virtual ICollection<<#= targetType #>> <#= navigation.Name #> { get; } = new ObservableCollection<<#= targetType #>>();

Musíme také přidat direktivu using do vygenerovaného kódu. Použití jsou zadána v seznamu v horní části šablony. Přidejte do seznamu System.Collections.ObjectModel.

var usings = new List<string>
{
    "System",
    "System.Collections.Generic",
    "System.Collections.ObjectModel"
};

Otestujte změny pomocí příkazů zpětné analýzy. Šablony ve vašem projektu jsou automaticky používány příkazy.

dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer

Pokud jste příkaz spustili dříve, přidejte --force možnost přepsání existujících souborů.

Pokud jste všechno udělali správně, měly by se teď používat navigační vlastnosti kolekce ObservableCollection<T>.

public virtual ICollection<Album> Albums { get; } = new ObservableCollection<Album>();

Aktualizace šablon

Když do projektu přidáte výchozí šablony, vytvoří jejich kopii na základě této verze EF Core. Protože chyby jsou opravené a funkce se přidávají v dalších verzích EF Core, můžou se vaše šablony stát zastaralými. Měli byste zkontrolovat změny provedené v šablonách EF Core a sloučit je do přizpůsobených šablon.

Jedním ze způsobů, jak zkontrolovat změny provedené v šablonách EF Core, je použití Gitu k porovnání mezi verzemi. Následující příkaz naklonuje úložiště EF Core a vygeneruje rozdíl těchto souborů mezi verzemi 7.0.0 a 8.0.0.

git clone --no-checkout https://github.com/dotnet/efcore.git
cd efcore
git diff v7.0.0 v8.0.0 -- src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.tt

Dalším způsobem, jak zkontrolovat změny, je stáhnout dvě verze Microsoft.EntityFrameworkCore.Templates z NuGetu, extrahovat jejich obsah (přípony souborů můžete změnit na .zip) a porovnat tyto soubory.

Před přidáním výchozích šablon do nového projektu nezapomeňte aktualizovat nejnovější balíček šablon EF Core.

dotnet new update

Pokročilé využití

Ignorování vstupního modelu

Parametry Model a EntityType představují jeden možný způsob mapování na databázi. Můžete se rozhodnout ignorovat nebo změnit části modelu. Například názvy navigace, které poskytujeme, nemusí být ideální a při generování kódu je můžete nahradit vlastními názvy. Další věci, jako jsou názvy omezení a filtry indexů, používají jenom migrace, a pokud nemáte v úmyslu používat migrace s vygenerovaným kódem, můžete je v modelu bezpečně vynechat. Podobně můžete chtít vynechat sekvence nebo výchozí omezení, pokud je vaše aplikace nepoužívá.

Při provádění pokročilých změn, jako je tato, stačí zajistit, aby výsledný model zůstal kompatibilní s databází. Kontrola SQL vygenerovaného dbContext.Database.GenerateCreateScript() je dobrý způsob, jak to ověřit.

Třídy konfigurace entit

U velkých modelů může být metoda OnModelCreating třídy DbContext nespravovatelně velká. Jedním ze způsobů, jak to vyřešit, je použití IEntityTypeConfiguration<T> tříd. Další informace o těchto třídách najdete v tématu Vytvoření a konfigurace modelu.

Pro generování těchto tříd můžete použít třetí šablonu s názvem EntityTypeConfiguration.t4. Podobně jako šablona EntityType.t4 se používá pro každý typ entity v modelu a používá parametr šablony EntityType.

Generování tabulky propojení ve vztazích M:N

Ve výchozím nastavení proces generování kódu negeneruje entitu pro spojovací tabulky v jednoduchých relacích M:N. Existují však případy, kdy explicitně vygenerování tabulky spojení jako entity může být nezbytné (například pokud je vyžadována kontrola nad vygenerovaným dotazem SQL).

Chování scaffoldingu pro každou entitu je řízeno souborem šablony EntityType.t4. V tomto souboru je podmínka, která přeruší generování entit pro jednoduché M:N spojovací tabulky. Pokud chcete toto chování přepsat a vygenerovat entitu spojení, můžete tuto podmínku okomentovat v souboru EntityType.t4.

<#
    // Comment this condition
    if (EntityType.IsSimpleManyToManyJoinEntityType())
    {
        // Don't scaffold these
        return "";
    }
    .  .  .    
#>

Generování dalších typů souborů

Primárním účelem zpětné analýzy v EF Core je generování typů DbContext a entit. V nástrojích ale není nic, co by vyžadovalo skutečné generování kódu. Můžete například místo toho vytvořit diagram vztahů entit pomocí Mermaid.

<#@ output extension=".md" #>
<#@ assembly name="Microsoft.EntityFrameworkCore" #>
<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #>
<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #>
<#@ parameter name="Model" type="Microsoft.EntityFrameworkCore.Metadata.IModel" #>
<#@ parameter name="Options" type="Microsoft.EntityFrameworkCore.Scaffolding.ModelCodeGenerationOptions" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="Microsoft.EntityFrameworkCore" #>
# <#= Options.ContextName #>

```mermaid
erDiagram
<#
    foreach (var entityType in Model.GetEntityTypes().Where(e => !e.IsSimpleManyToManyJoinEntityType()))
    {
#>
    <#= entityType.Name #> {
    }
<#
        foreach (var foreignKey in entityType.GetForeignKeys())
        {
#>
    <#= entityType.Name #> <#= foreignKey.IsUnique ? "|" : "}" #>o--<#= foreignKey.IsRequired ? "|" : "o" #>| <#= foreignKey.PrincipalEntityType.Name #> : "<#= foreignKey.GetConstraintName() #>"
<#
        }

        foreach (var skipNavigation in entityType.GetSkipNavigations().Where(n => n.IsLeftNavigation()))
        {
#>
    <#= entityType.Name #> }o--o{ <#= skipNavigation.TargetEntityType.Name #> : <#= skipNavigation.JoinEntityType.Name #>
<#
        }
    }
#>
```