Udostępnij za pośrednictwem


Niestandardowe szablony inżynierii odwrotnej

Uwaga

Ta funkcja została dodana w programie EF Core 7.

Podczas gdy inżynieria odwrotna, platforma Entity Framework Core dąży do tworzenia szkieletów dobrego kodu ogólnego przeznaczenia, który może być używany w różnych typach aplikacji i używa wspólnych konwencji kodowania w celu spójnego wyglądu i znanego działania. Czasami jednak bardziej wyspecjalizowany kod i alternatywne style kodowania są pożądane. W tym artykule pokazano, jak dostosować kod szkieletowy przy użyciu szablonów tekstu T4.

Wymagania wstępne

W tym artykule założono, że znasz inżynierię odwrotną w programie EF Core. Jeśli nie, przed kontynuowaniem zapoznaj się z tym artykułem.

Dodawanie szablonów domyślnych

Pierwszym krokiem dostosowywania kodu szkieletowego jest dodanie domyślnych szablonów do projektu. Domyślne szablony są używane wewnętrznie przez program EF Core podczas inżynierii odwrotnej. Zapewniają one punkt wyjścia do rozpoczęcia dostosowywania kodu szkieletowego.

Zacznij od zainstalowania pakietu szablonu programu EF Core dla dotnet newprogramu :

dotnet new install Microsoft.EntityFrameworkCore.Templates

Teraz możesz dodać szablony domyślne do projektu. W tym celu uruchom następujące polecenie z katalogu projektu.

dotnet new ef-templates

To polecenie dodaje następujące pliki do projektu.

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

Szablon DbContext.t4 służy do tworzenia szkieletu klasy DbContext dla bazy danych, a EntityType.t4 szablon służy do tworzenia szkieletu klas typów jednostek dla każdej tabeli i widoku w bazie danych.

Napiwek

Rozszerzenie .t4 jest używane (zamiast .tt), aby uniemożliwić programowi Visual Studio przekształcanie szablonów. Zamiast tego szablony zostaną przekształcone przez program EF Core.

Wprowadzenie do T4

Otwórzmy DbContext.t4 szablon i sprawdźmy jego zawartość. Ten plik jest szablonem tekstowym T4. T4 to język do generowania tekstu przy użyciu platformy .NET. Poniższy kod służy tylko do celów ilustracyjnych; nie reprezentuje pełnej zawartości pliku.

Ważne

Szablony tekstu T4 — szczególnie te, które generują kod — mogą być trudne do odczytania bez wyróżniania składni. W razie potrzeby wyszukaj rozszerzenie w edytorze kodu, które umożliwia wyróżnianie składni 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 #>;

Pierwsze kilka wierszy rozpoczynających <#@ się od są nazywane dyrektywami. Wpływają one na sposób przekształcania szablonu. W poniższej tabeli krótko opisano każdy rodzaj używanej dyrektywy.

Dyrektywa opis
template Określa hostSpecific="true", który umożliwia korzystanie z Host właściwości wewnątrz szablonu w celu uzyskania dostępu do usług EF Core.
assembly Dodaje odwołania do zestawu wymagane do skompilowania szablonu.
parameter Deklaruje parametry, które zostaną przekazane przez program EF Core podczas przekształcania szablonu.
import Podobnie jak w języku C# przy użyciu dyrektyw, przestrzenie nazw są w zakresie kodu szablonu.

Po dyrektywach następna sekcja jest DbContext.t4 nazywana blokiem sterującym. Standardowy blok kontrolny zaczyna się od i kończy się <# ciągiem #>. Kod w nim zostanie wykonany podczas przekształcania szablonu. Aby uzyskać listę właściwości i metod dostępnych wewnątrz bloków sterowania, zobacz klasę TextTransformation .

Wszystkie elementy spoza bloku sterowania zostaną skopiowane bezpośrednio do danych wyjściowych szablonu.

Blok kontrolki wyrażenia zaczyna się od <#=. Kod w nim zostanie oceniony, a wynik zostanie dodany do danych wyjściowych szablonu. Są one podobne do argumentów ciągów interpolowanych w języku C#.

Aby uzyskać bardziej szczegółowe i pełne wyjaśnienie składni T4, zobacz Pisanie szablonu tekstowego T4.

Dostosowywanie typów jednostek

Przyjrzyjmy się, jak jest to zrobić, aby dostosować szablon. Domyślnie program EF Core generuje następujący kod dla właściwości nawigacji kolekcji.

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

Użycie List<T> jest dobrym ustawieniem domyślnym dla większości aplikacji. Jeśli jednak używasz platformy opartej na języku XAML, takiej jak WPF, WinUI lub .NET MAUI, często chcesz użyć jej ObservableCollection<T> do włączenia powiązania danych.

EntityType.t4 Otwórz szablon i znajdź miejsce wygenerowania List<T>pliku . Wygląda to tak:

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

Zastąp element List elementem ObservableCollection.

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

Musimy również dodać dyrektywę using do kodu szkieletowego. Użycie jest określone na liście w górnej części szablonu. Dodaj System.Collections.ObjectModel do listy.

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

Przetestuj zmiany przy użyciu poleceń inżynierii odwrotnej. Szablony w projekcie są używane automatycznie przez polecenia.

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

Jeśli wcześniej uruchomiono polecenie, dodaj --force opcję zastąpienia istniejących plików.

Jeśli wszystko zostało wykonane poprawnie, właściwości nawigacji kolekcji powinny teraz używać polecenia ObservableCollection<T>.

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

Aktualizowanie szablonów

Po dodaniu domyślnych szablonów do projektu zostanie utworzona kopia na podstawie tej wersji programu EF Core. Ponieważ usterki są stałe, a funkcje są dodawane w kolejnych wersjach programu EF Core, szablony mogą stać się nieaktualne. Należy przejrzeć zmiany wprowadzone w szablonach platformy EF Core i scalić je z dostosowanymi szablonami.

Jednym ze sposobów przeglądania zmian wprowadzonych w szablonach platformy EF Core jest użycie narzędzia git do porównywania ich między wersjami. Następujące polecenie sklonuje repozytorium EF Core i wygeneruje różnicę tych plików między wersjami 7.0.0 i 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

Innym sposobem na przejrzenie zmian jest pobranie dwóch wersji szablonów Microsoft.EntityFrameworkCore.Templates z narzędzia NuGet, wyodrębnienie ich zawartości (można zmienić rozszerzenia plików na plik zip) i porównanie tych plików.

Przed dodaniem szablonów domyślnych do nowego projektu pamiętaj, aby zaktualizować go do najnowszego pakietu szablonu platformy EF Core.

dotnet new update

Użycie zaawansowane

Ignorowanie modelu wejściowego

Parametry Model i EntityType reprezentują jeden możliwy sposób mapowania na bazę danych. Możesz zignorować lub zmienić części modelu. Na przykład podane nazwy nawigacji mogą nie być idealne i można je zastąpić własnymi elementami podczas tworzenia szkieletu kodu. Inne elementy, takie jak nazwy ograniczeń i filtry indeksów, są używane tylko przez migracje i można bezpiecznie pominąć z modelu, jeśli nie zamierzasz używać migracji ze szkieletem kodu. Podobnie możesz pominąć sekwencje lub domyślne ograniczenia, jeśli nie są one używane przez aplikację.

Podczas wprowadzania zaawansowanych zmian w ten sposób upewnij się, że wynikowy model pozostaje zgodny z bazą danych. Przeglądanie kodu SQL wygenerowanego przez dbContext.Database.GenerateCreateScript() program jest dobrym sposobem na zweryfikowanie tego elementu.

Klasy konfiguracji jednostek

W przypadku dużych modeli metoda OnModelCreating klasy DbContext może stać się niezarządzana. Jednym ze sposobów rozwiązania tego problemu jest użycie IEntityTypeConfiguration<T> klas. Aby uzyskać więcej informacji na temat tych klas, zobacz Tworzenie i konfigurowanie modelu .

Aby utworzyć szkielet tych klas, możesz użyć trzeciego szablonu o nazwie EntityTypeConfiguration.t4. EntityType.t4 Podobnie jak szablon, jest używany dla każdego typu jednostki w modelu i używa parametru szablonuEntityType.

Tworzenie szkieletów innych typów plików

Podstawowym celem inżynierii odwrotnej w programie EF Core jest utworzenie szkieletu typu DbContext i jednostki. Jednak nie ma nic w narzędziach, które wymagają faktycznego tworzenia szkieletu kodu. Na przykład można zamiast tego utworzyć szkielet diagramu relacji jednostki przy użyciu Syreny.

<#@ 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 #>
<#
        }
    }
#>
```