Пользовательские шаблоны обратной инженерии
Примечание.
Эта функция была добавлена в EF Core 7.
В то время как обратная инженерия Entity Framework Core стремится создать хороший код общего назначения, который можно использовать в различных типах приложений и использует общие соглашения по программированию для согласованного внешнего вида и знакомого интерфейса. Однако иногда желательно использовать более специализированный код и альтернативные стили программирования. В этой статье показано, как настроить шаблонный код с помощью текстовых шаблонов T4.
Необходимые компоненты
В этой статье предполагается, что вы знакомы с обратным проектированием в EF Core. Если нет, ознакомьтесь с этой статьей, прежде чем продолжить.
Добавление шаблонов по умолчанию
Первым шагом в настройке шаблонного кода является добавление шаблонов по умолчанию в проект. Шаблоны по умолчанию используются внутри EF Core при обратном проектировании. Они предоставляют отправную точку для начала настройки шаблонного кода.
Начните с установки пакета шаблона EF Core для dotnet new
:
dotnet new install Microsoft.EntityFrameworkCore.Templates
Теперь вы можете добавить шаблоны по умолчанию в проект. Для этого выполните следующую команду из каталога проекта.
dotnet new ef-templates
Эта команда добавляет в проект следующие файлы.
- CodeTemplates/
- EFCore/
- DbContext.t4
- EntityType.t4
- EFCore/
Шаблон DbContext.t4
используется для формирования класса DbContext для базы данных, а EntityType.t4
шаблон используется для формирования классов типов сущностей для каждой таблицы и просмотра в базе данных.
Совет
Расширение .t4 используется (вместо .tt), чтобы предотвратить преобразование шаблонов в Visual Studio. Вместо этого шаблоны будут преобразованы EF Core.
Общие сведения о T4
Давайте открываем DbContext.t4
шаблон и проверяем его содержимое. Этот файл представляет собой текстовый шаблон T4. T4 — это язык для создания текста с помощью .NET. Следующий код предназначен только для иллюстрирующих целей; Он не представляет полного содержимого файла.
Важно!
Текстовые шаблоны T4, особенно те, которые создают код, могут быть трудно читать без выделения синтаксиса. При необходимости найдите расширение в редакторе кода, который включает выделение синтаксиса 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 #>;
Первые несколько строк, начинающихся с <#@
, называются директивами. Они влияют на преобразование шаблона. В следующей таблице кратко описывается каждый тип используемой директивы.
Директива | Description |
---|---|
template |
Указывает hostSpecific="true", который позволяет использовать Host свойство внутри шаблона для доступа к службам EF Core. |
assembly |
Добавляет ссылки на сборки, необходимые для компиляции шаблона. |
parameter |
Объявляет параметры, которые будут передаваться EF Core при преобразовании шаблона. |
import |
Как и директивы C#, переносят пространства имен в область для кода шаблона. |
После директив следующий раздел DbContext.t4
называется блоком управления. Стандартный блок управления начинается <#
и заканчивается #>
. Код внутри него будет выполнен при преобразовании шаблона. Список свойств и методов, доступных внутри блоков управления, см. в классе TextTransformation .
Все, что находится за пределами блока управления, будет скопировано непосредственно в выходные данные шаблона.
Блок управления выражением начинается с <#=
. Код внутри него будет вычисляться, и результат будет добавлен в выходные данные шаблона. Они похожи на интерполированные строковые аргументы C#.
Более подробное и полное описание синтаксиса T4 см. в статье "Написание текстового шаблона T4".
Настройка типов сущностей
Давайте рассмотрим, как это сделать, чтобы настроить шаблон. По умолчанию EF Core создает следующий код для свойств навигации коллекции.
public virtual ICollection<Album> Albums { get; } = new List<Album>();
Использование List<T>
является хорошим по умолчанию для большинства приложений. Однако если вы используете платформу на основе XAML, например WPF, WinUI или .NET MAUI, вместо этого необходимо включить ObservableCollection<T>
привязку данных.
EntityType.t4
Откройте шаблон и найдите место его созданияList<T>
. Он будет выглядеть примерно так:
if (navigation.IsCollection)
{
#>
public virtual ICollection<<#= targetType #>> <#= navigation.Name #> { get; } = new List<<#= targetType #>>();
<#
}
Замените список на ObservableCollection.
public virtual ICollection<<#= targetType #>> <#= navigation.Name #> { get; } = new ObservableCollection<<#= targetType #>>();
Также необходимо добавить директиву using
в шаблонный код. Использование указывается в списке в верхней части шаблона. Добавьте System.Collections.ObjectModel
в список.
var usings = new List<string>
{
"System",
"System.Collections.Generic",
"System.Collections.ObjectModel"
};
Проверьте изменения с помощью команд обратной инженерии. Шаблоны внутри проекта используются автоматически командами.
dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
Если вы ранее выполнили команду, добавьте --force
параметр для перезаписи существующих файлов.
Если вы сделали все правильно, теперь свойства навигации коллекции должны использоваться ObservableCollection<T>
.
public virtual ICollection<Album> Albums { get; } = new ObservableCollection<Album>();
Обновление шаблонов
При добавлении шаблонов по умолчанию в проект он создает копию этих шаблонов на основе этой версии EF Core. Так как ошибки исправлены и функции добавляются в последующих версиях EF Core, шаблоны могут стать устаревшими. Необходимо просмотреть изменения, внесенные в шаблоны EF Core, и объединить их в настраиваемые шаблоны.
Одним из способов проверки изменений, внесенных в шаблоны EF Core, является использование git для сравнения версий. Следующая команда клонирует репозиторий EF Core и создает дифф этих файлов между версиями 7.0.0 и 8.0.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
Другим способом проверки изменений является скачивание двух версий Microsoft.EntityFrameworkCore.Templates из NuGet, извлечение их содержимого (можно изменить расширения файлов на ZIP-файл и сравнить эти файлы.
Прежде чем добавлять шаблоны по умолчанию в новый проект, не забудьте обновить до последнего пакета шаблонов EF Core.
dotnet new update
Расширенное использование
Игнорировать входную модель
EntityType
Параметры Model
представляют собой один из возможных способов сопоставления с базой данных. Вы можете игнорировать или изменять части модели. Например, имена навигации, которые мы предоставляем, могут быть не идеальными, и их можно заменить собственными при создании шаблонов кода. Другие вещи, такие как имена ограничений и фильтры индексов, используются только миграциями и могут быть безопасно опущены из модели, если вы не планируете использовать миграции с шаблонным кодом. Аналогичным образом, может потребоваться опустить последовательности или ограничения по умолчанию, если они не используются приложением.
При внесении дополнительных изменений, как это, просто убедитесь, что результирующая модель остается совместимой с базой данных. Проверка SQL, созданного с помощью dbContext.Database.GenerateCreateScript()
, является хорошим способом проверки этого.
Классы конфигурации сущностей
Для больших моделей метод OnModelCreating класса DbContext может стать неуправляемым. Одним из способов решения этой проблемы является использование IEntityTypeConfiguration<T>
классов. Дополнительные сведения об этих классах см. в статье "Создание и настройка модели ".
Для формирования шаблонов этих классов можно использовать третий шаблон EntityTypeConfiguration.t4
. EntityType.t4
Как и шаблон, он используется для каждого типа сущности в модели и использует EntityType
параметр шаблона.
Создание шаблонов других типов файлов
Основной целью реверсивного проектирования в EF Core является создание шаблонов dbContext и типов сущностей. Тем не менее, нет ничего в средствах, которые требуют, чтобы на самом деле создать шаблон кода. Например, вместо этого можно создать шаблон схемы связей сущностей с помощью 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 #>
<#
}
}
#>
```