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:
|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.
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
Scaffold-DbContext ` ..\ChinookDatabase\bin\Debug\ChinookDatabase.dacpac ` ErikEJ.EntityFrameworkCore.SqlServer.Dacpac ` -OutputDir Models ` -ContextDir Data ` -Force
In addition to all the usual T4 goodness, the following helpers are also available.
|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
|Code.Fragment||Generates code from fragments returned by the
|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
builder.HasKey(<#= Code.Lambda(primaryKey.Properties) #>);
builder.HasKey(x => x.Id);