EFCore.TextTemplating
This sample shows how to use T4 templates to scaffold code when reverse engineering a model from a database using EF Core.
This repo contains three projects:
Project | Description |
---|---|
ChinookApp | An example app containing the scaffolded DbContext type, configuration, and entity types |
ChinookDatabase | The database project for our example app |
EFCore.TextTemplating | Contains the T4 templates and required plumbing to hook them into EF Core. Copy into your solution to get started |
ChinookApp references EFCore.TextTemplating and contains an assembly-level attribute that EF Core uses to discover its design-time services. Your app needs to do this too:
[assembly: DesignTimeServicesReference(
"EFCore.TextTemplating.DesignTimeServices, EFCore.TextTemplating")]
ChinookApp also references the EF Core tools and my pluralizer extension to enhance the scaffolded code and ErikEJ.EntityFrameworkCore.SqlServer.Dacpac from the EF Core Power Tools to reverese engineer directly from a DACPAC.
EFCore.TextTemplating contains three templates: one for scaffolding the DbContext, one for the IEntityTypeConfiguration implementations, and one for the entity types.
The templates in this repo are merely a starting point. Feel free to tweak them to your heart's content. The resulting code is a little ugly, but I refrained from adding formatting code to keep the templates as simple as possible. I scaffold the code I would want to use, so only the parts of the model that actually affect EF Core behavior are scaffolded. Things like sequences, constraint names, and non-unique indexes are ignored.
If you're using Visual Studio, merely saving the template files is enough.
If you're using VS Code, you'll need to use dotnet-t4 after editing the files:
dotnet tool install -g dotnet-t4
t4 MyDbContextGenerator.tt -c MyDbContextGenerator -o MyDbContextGenerator.cs
Reverse engineering the model can be done in the normal way:
dotnet ef dbcontext scaffold \
../ChinookDatabase/bin/Debug/ChinookDatabase.dacpac \
ErikEJ.EntityFrameworkCore.SqlServer.Dacpac \
--output-dir Models \
--context-dir Data \
--force
or
Scaffold-DbContext `
..\ChinookDatabase\bin\Debug\ChinookDatabase.dacpac `
ErikEJ.EntityFrameworkCore.SqlServer.Dacpac `
-OutputDir Models `
-ContextDir Data `
-Force
API Reference
In addition to all the usual T4 goodness, the following helpers are also available.
Method | Description |
---|---|
AnnotationCode.IsHandledByConvention | Gets a value indicating whether the annotation would be handled by convention. If so, generating code is unnecessary |
AnnotationCode.GenerateFluentApi | Generates provider-specific fluent API for the given annotation (like .IsClustered() ) |
Code.Fragment | Generates code from fragments returned by the ProviderCode and AnnotationCode helpers |
Code.Identifier | Generates a valid identifier unique within the given scope |
Code.Lambda | Generates a property access lambda |
Code.Literal | Generates a literal for given value |
Code.Namespace | Generates a valid namespace from its given parts |
Code.Reference | Generates a C# reference to the given type |
Code.UnknownLiteral | Generates a literal for a value whose type isn't known at compile time |
ProviderCode.GenerateUseProvide | Generates the DbContextOptions code to configure the provider (like .UseSqlServer("Data Source=...") ) |
For example:
Input
builder.HasKey(<#= Code.Lambda(primaryKey.Properties) #>);
Output
builder.HasKey(x => x.Id);