Customize the DevForce code generation template when you need fine control over the entity class code generated for your Entity Data Model (EDM).
DevForce code generation uses the .NET Text Template Transformation Toolkit (T4) to customize code generation. DevForce ships with a default T4 template that is used for all code generation. Like most T4 templates provided by Microsoft and other vendors, this template can be replaced with a custom version. Custom versions are usually a copy of the default template with some minor modifications.
While DevForce supports this approach, we provide what we believe to be a better approach. Instead of modifying the template, you subclass the core template generator class, DomainModelTemplate, overriding only those portions which requires custom treatment. Virtually every major code generation region within your generated code corresponds to a virtual method within this class.
Deriving from DomainModelTemplate is much easier than writing raw T4 source code:
The source code for DomainModelTemplate is shipped with DevForce; find it in the DevForce installation directory.
When you add an Entity Framework EDMX, DevForce adds its T4 template to the project, modifying it slightly to reflect the specifics of your model.
A typical example looks something like the following in Visual Studio 2010:
T4 | <#@ template language="C#" debug="true" hostSpecific="true" #> <#@ output extension=".ReadMe" #> <#@ Assembly Name="IdeaBlade.VisualStudio.OM.CodeGenerator.dll" #> <#@ import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator" #> <# // Source for this file located at: C:\Users\...\AppData\Local\Microsoft\VisualStudio\10.0\Extensions\IdeaBlade, Inc\IdeaBlade OM Designer Extension\6.1.9.0\DomainModelTemplate.tt // NorthwindIB.edmx <--- This is needed so that "Transform Related Text Templates On Save" works correctly. var template = new DomainModelTemplate(this); template.Generate(); #> <#+ #> |
... and in Visual Studio 2012 (note the changed assembly name):
T4 | <#@ template language="C#" debug="true" hostSpecific="true" #> <#@ output extension=".ReadMe" #> <#@ Assembly Name="IdeaBlade.VisualStudio.OM.CodeGeneratorV6.11.0.dll" #> <#@ import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator" #> <# // Source for this file located at: C:\USERS\...\APPDATA\LOCAL\MICROSOFT\VISUALSTUDIO\11.0\EXTENSIONS\...\DomainModelTemplate.tt // NorthwindIB.edmx <--- This is needed so that "Transform Related Text Templates On Save" works correctly. var template = new DomainModelTemplate(this); template.Generate(); #> <#+ #> |
The template delegates the work to IdeaBlade.VisualStudio.OM.CodeGenerator.DomainModelTemplate class about five lines from the bottom..
There are three steps to customizing this template:
You get a working template at every step. You can stop after steps #1 or step #2 if you wish. We recommend you go all the way to step #3.
Before starting, you must install the Visual Studio 2010 SDK to get the Microsoft.VisualStudio.TextTemplating library. Install the right SDK for you version of Visual Studio, either Visual Studio 2010 or Visual Studio 2010 SP1.
You are going to subclass the DomainModelTemplate class inside the project's .tt file.
First, add two assembly references
Next, find the declaration of the template variable and set it with your new template generator class
Finally, write the code for your template generator class directly below the old code as seen in this example:
T4 | <#@ template language="C#" debug="true" hostSpecific="true" #> <#@ output extension="./DontReadMe" #> <#@ Assembly Name="Microsoft.VisualStudio.TextTemplating.10.0" #> <#@ Assembly Name="IdeaBlade.Core" #> ... // SimpleNorthwind.edmx <--- Needed so "Transform Related Text Templates On Save" works correctly. var template = new MyTemplate(this); template.Generate(); #> <#+ public class MyTemplate : DomainModelTemplate { public MyTemplate(Microsoft.VisualStudio.TextTemplating.TextTransformation textTransformation) : base(textTransformation) {} protected override void WriteEntityDataPropertyAttributes(EdmPropertyWrapper property) { WriteAttribute("Foo(" + Quote(property.Name) + ")"); base.WriteEntityDataPropertyAttributes(property); } } #> |
MyTemplate() replaces DomainModelTemplate and overrides the base WriteEntityDataPropertyAttributes method to add Foo.
While writing the MyTemplate class within the template itself is certainly easy to do, we don't recommended it.
First, this customization only works for the specific EDMX to which it is attached. SimpleNorthwind.edmx, the name of this project's EDMX file, is baked into the .tt file. If you change the name of the EDMX file you'll have to change change this .tt file as well. You won't be able to re-use this custom MyTemplate class for other models and applications.
Second, you don't get any help from Intellisense while you're writing MyTemplate; it's difficult to edit a template file with any significant amount of code this way.
Let's fix the first problem first.
The DevForce EDM Designer Extension looks for a file named DomainModelTemplate.tt in a well-known place. DomainModelTemplate.tt is actually a template for making .tt templates. It has placeholder tokens for model-specific values. It's the file the DevForce Designer Extension used to create the SimpleNorthwind.edmx.tt file in the model project.
The goal is to replace the existing DomainModelTemplate.tt file with your version so that the next time DevForce generates a entity classes from a model ... any model ... it creates a .tt file based on your template file.
DomainModelTemplate.tt is in another directory, the one mentioned in a comment of the .tt you edited.
TT | // Source for this file located at: // C:\Users\...\AppData\Local\Microsoft\VisualStudio\10.0\Extensions\IdeaBlade, Inc\ // IdeaBlade OM Designer Extension\6.0.5.0\DomainModelTemplate.tt |
The actual directory location varies according to machine, operating system, and user name.
Now edit this new version of DomainModelTemplate.tt to put in the placeholder tokens.
Change:
TT | // Source for this file located at: // C:\Users\...\AppData\Local\Microsoft\VisualStudio\10.0\Extensions\IdeaBlade, Inc\ // IdeaBlade OM Designer Extension\6.0.5.0\DomainModelTemplate.tt // SimpleNorthwind.edmx <--- Needed so "Transform Related Text Templates On Save" works correctly. |
To:
TT | // Source for this file located at: $templateFullFileName$ // $edmxname$ <--- Needed so "Transform Related Text Templates On Save" works correctly. |
All future .tt files created for any model project will be based on this new template.
You can also update an older project that was generated with the old template version.
This triggers recreation of the EDMX's .tt file and regenerates your model using the new template.
This third step builds on the second.
The goal is to be able to edit your custom template generator in Visual Studio so you can take advantage of Intellisense, type-checking, and Visual Studio debugging.
You will extract your custom MyTemplate class from the template and put it in its own assembly.
Create a new project. Let's call it MyTemplateAssembly. Then create the MyTemplate class from the code you wrote earlier.
C# | using IdeaBlade.EntityModel.Edm.Metadata; using IdeaBlade.VisualStudio.OM.CodeGenerator; namespace MyTemplateAssembly { public class MyTemplate : DomainModelTemplate { public MyTemplate(Microsoft.VisualStudio.TextTemplating.TextTransformation textTransformation) : base(textTransformation) {} protected override void WriteEntityDataPropertyAttributes(EdmPropertyWrapper property) { WriteAttribute("Foo(" + Quote(property.Name) + ")"); base.WriteEntityDataPropertyAttributes(property); } } } |
VB | Imports IdeaBlade.EntityModel.Edm.Metadata Imports IdeaBlade.VisualStudio.OM.CodeGenerator Public Class MyTemplate Inherits DomainModelTemplate Public Sub New(ByVal textTransformation As _ Microsoft.VisualStudio.TextTemplating.TextTransformation) MyBase.New(textTransformation) End Sub Protected Overrides Sub WriteEntityDataPropertyAttributes( _ ByVal property1 As EdmPropertyWrapper) WriteAttribute("Foo(" & Quote(property1.Name) & ")") MyBase.WriteEntityDataPropertyAttributes(property1) End Sub End Class |
Make a new version of DomainModelTemplate.tt from the original backup copy.
Edit this DomainModelTemplate.tt file to use your custom template generator.
The final DomainModelTemplate.tt would look something like this:
T4 | <#@ template language="C#" debug="true" hostSpecific="true" #> <#@ output extension="./DontReadMe" #> <#@ Assembly Name=”{path to MyTemplateAssembly}” #> <#@ Assembly Name="IdeaBlade.VisualStudio.OM.CodeGenerator.dll" #> <#@ import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator" #> <#@ import namespace="MyTemplateAssembly" #> <# // Source for this file located at: $templateFullFileName$ // $edmxname$ <--- Needed so "Transform Related Text Templates On Save" works correctly. var template = new MyTemplate(this); template.Generate(); #> <#+ #> |
Notice that you must spell out the full path to your assembly reference: <#@ Assembly Name=”{path to MyTemplateAssembly}” #>/
Congratulations! You're done! Future .tt files created for a model project will be based on your new template and you'll be able to maintain that template efficiently in Visual Studio.