Blog Series: Model Driven Development with T4 templates – Part 3
Date: Tuesday, February 19, 2013 8:33 AM
Posted by: Nico Ploner
Category: T4
Part three of this blog series creates data objects based on the domain specific model we build in the previous part. Instead of writing all class code by hand we’re going to implement a reusable T4 template that transforms the model diagram into C# data classes for EntityFramework CodeFirst.
Following to this blog post we’re going to create data persistence layer based on this data classes and a basic user interface using another T4 template.
Blog Series Overview
Part 1: Model Driven Development and Series Overview
Part 2: Create a Persistence Model using Tangible Modeling Tools
Part 3: Generating Domain Specific data objects using T4 and EntityFramework 5 CodeFirst
Part 4: Data Persistence and Versioning
Part 5: Generate a Basic UI using T4 and Windows Presentation Foundation
In this Part
The Entity Framework CodeFirst model
Create a T4 template for data classes
The Entity Framework CodeFirst model
The ADO.NET Entity Framework is Microsoft’s open source O/R-Mapping technology, relieving the developer from caring about how data is stored in a relational database. Thus developers can focus on creating data-oriented applications by their well-known concepts of domain specific data objects.
Usually the Entity Framework is used in a ModelFirst approach in which the domain specific model is created using a visual entity model designer or derived from an existing database scheme. Based on this model code classes are generated that the developer can use to display data in the user interface.
Unfortunately the code generated by the entity model designer cannot easily be adapted to match the developer’s needs – for example if the developer wants the code classes to use a special collection type to be used when creating associations between two data classes.
That is where the CodeFirst approach fits in. In contrast to ModelFirst the developer writes the code classes manually and then creates the database from those classes. That way the developer is free to implement the code classes as needed.
Persistent Object Diagram and CodeFirst
When writing code classes manually the developer needs to repeat writing the same code fragments over and over again. And if there’s something to be changed later on, every existing line of code every existing line of code needs to be revised.
This is where we employ code generation again: Using a tangible Persistent Object Diagram as an input file with a customized T4 template, we automatically generate CodeFirst code classes that define that database structure later on. The same code classes are used to display data information in the user interface.
This results in three advantages: First, we’re using a model based approach, which eases the communication between stakeholders using a visual representation and is easy to adapt. Second, we’re using CodeFirst code classes, which is comfortable for developers, and third, we’re using code generation, allowing changes to be easily applied to the existing code model.
T4 Templates
T4 stands for “Text Template Transformation Toolkit” and is a text generation framework that comes with Visual Studio. This toolkit allows the generation of any text format like C#, XML, HTML, etc. structured by code written in C# or VB. Unfortunately there is no editing experience included in Visual Studio, but text transformation is fully supported. Our tangible T4 Editor extends this functionality so you can comfortably edit T4 files with syntax highlighting, auto completion and IntelliSense.
In our model driven scenario we’re going to use the Persistent Object Model (the .tasl file we generated in the last part) as an input for a T4 template. Although the .tasl file is an XML based file and we could open and iterate it with an XML parser, we’re going to use another feature of tangible’s T4 Editor, that allows us to access the Persistent Object Model via code classes inside the T4.
Create a T4 template for data classes
This section provides you with a step-by-step manual how to create a T4 template transforming a tangible Persistent Object Model into Entity Framework CodeFirst code classes. But first we’re going to look at, what the expected code result should look like.
As a reminder: this is the domain specific model we are going to transform into C# code classes:
Desired Result
In order to use the Entity Framework as an O/R-Mapper accessing a given database, we need a so called “Context” class that knows how to map code classes to database tables and columns. We create a C# class for it, inheriting from System.Data.Entity.DbContext that contains a DbSet for every persistent object modeled in the .tasl file.
public class Context : System.Data.Entity.DbContext
{
public Context(string connectionString) : base(connectionString) { }
public DbSet<Bank> Banks { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Account> Accounts { get; set; }
public DbSet<CashCard> CashCards { get; set; }
}
And then we need to create a C# class for each Persistent Object that we want to use in the user interface and manipulate data with. This is the expected code for the CashCard object as a UI bindable C# class:
public class CashCard : System.ComponentModel.INotifyPropertyChanged
{
private int _Id;
[System.ComponentModel.DataAnnotations.Key]
public int Id
{
get { return _Id; }
set { _Id = value; OnPropertyChanged("Id"); }
}
private System.DateTime _Expiration;
public System.DateTime Expiration
{
get { return _Expiration; }
set { _Expiration = value; OnPropertyChanged("Expiration"); }
}
private string _PIN;
public string PIN
{
get { return _PIN; }
set { _PIN = value; OnPropertyChanged("PIN"); }
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this,
new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
}
At this point you already can see how painful it will be, if one created a large amount of data classes by hand and afterwards noticed that e.g. the implementation of INotifyPropertyChanged was missing…
That’s why we’re going to use the functionality of T4 to generate the code classes. That means: if there is to fix something later, we only need to fix it in the template and all the code gets automatically repaired.
Building the T4 Template
Add Entity Framework Library
Before we can start to build the T4 template, we need to add the Entity Framework libraries in version 5 to our project. Inside Visual Studio Menu click “Tools” > “Library Pack Manager” > “Package Manager Console” and type “Install-Package EntityFramework” into the package manager console window.
Add new .tt File To Project
Right click your current project in the Solution Explorer and choose “Add” > “New Item”. Select a “Blank T4 Template” from the “tangible T4 Editor” category. Name it “TaslToCodeFirst.tt” and make sure it is placed beside your .tt file in the project.
Open the T4 template file in the tangible T4 Editor by double clicking its name in the Solution Explorer window and remove all existing lines.
Create Header Directives
Add a template directive that makes this T4 template inherit from ModelingTextTransformation and a TangiblePersistentObjectDiagram directive. This will allow you to access the Persistent Object Model by classes and properties inside the T4 template with auto completion and IntelliSense as you’re used to by Visual Studio. Provide the directive with the “BlogSeries.tasl” filename to our model file.
Set the output extension to “.cs” and import necessary namespaces and assemblies.
Your template should similar to this:
<#@ template
inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation"
debug="true"
hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ TangiblePersistentObjectDiagram
processor="TangiblePersistentObjectDiagramDirectiveProcessor"
requires="fileName='BlogSeries.tasl'"
provides="PersistentObjectModel" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="tasl.Dsl.10.dll" #>
<#@ import namespace="tasl.Dsl" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
Create Code for DbContext
Now we’re going to create template code that outputs c# code for the DbContext class
C# code inside <# … #> tags will be executed when the template is transformed. Text outside those tags (with white background color) will be written at the current position in the output file. Expressions inside <#= … #> tags will be evaluated and the result will be written in the output file.
So first we’re going to write the class definition, that will be simply copied into the output file. But inside the class definition we’re using a foreach loop iterating over all persistent objects and write the DbSet property for the persistent object.
Put the following code directly after the template header:
using System;
using System.Data.Entity;
using System.ComponentModel;
using System.Collections.ObjectModel;
public class Context : DbContext
{
public Context(string connectionString) : base(connectionString) { }
<# // create a list containing all persistent objects and the persistent root object
List<PersistentObjectBase> allPersistentObjects =
this.PersistentObjectModel.PersistentObjects.ToList<PersistentObjectBase>();
allPersistentObjects.Add(this.PersistentObjectModel.PersistentRootObject);
// iterate all persistent objects and create a DbSet property for it
foreach(var persistentObject in allPersistentObjects)
{
#> public DbSet<<#= persistentObject.Name #>> <#= persistentObject.Name #> { get; set; }
<# }
#>
}
If you transform the template so far, you’ll see that the result matches our desired output for the Context class mentioned above.
Create Code For Entity Classes
Now it’s getting a bit more complicated, because for the data classes we need to iterate all classes again, then create all scalar properties, all associations between the classes and the INotifyPropertyChanged interface.
So first let’s create the class stubs for the persistent object and then later extend the code.
<# foreach(var persistentObject in allPersistentObjects)
{
#> public class <#= persistentObject.Name #> : INotifyPropertyChanged
{
// 1: create scalar properties
// 2: create associations
// 3: implement INotifyPropertyChanged
}
<# }
#>
Implementing INotifyPropertyChanged is straight forward since there is no template logic necessary. Place the following code where the previous code snippet says “// 3: implement INotifyPropertyChanged”:
// 3: implement INotifyPropertyChanged
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
Now let’s have a look at the scalar properties. Properties are accessible directly via the persistent object through the Properties property. So inside the loop iterating all persistent objects we’re going to iterate all properties of that persistent object and output matching properties. The output code will store each property in a private member, expose it via a public property and make use of the NotifyPropertyChanged-Event.
Put the following code at “// 1: create scalar properties”:
// 1: create scalar properties
<# foreach(var property in persistentObject.Properties)
{
#> private <#= property.Type #> _<#= property.Name #>;
// 4: placeholder for [Key] attribute
public <#= property.Type #> <#= property.Name #>
{
get
{
return _<#= property.Name #>;
}
set
{
_<#= property.Name #> = value;
OnPropertyChanged("<#= property.Name #>");
}
}
<# }
#>
Remember how we created an extensible property in the diagram that allowed us to mark properties as “Identifier”? Now we need to access this extensible property in order to decorate those properties with the [Key] attribute used in the EntityFramework to design primary keys:
The property object has got a method named “GetExtensiblePropertyValue” that returns the value of an extensible property when the name of the extensible property is passed. Depending on the boolean value returned we’re going to output the [Key] attribute on the property.
Please replace the // 4: placeholder for [Key] attribute with the following code snippet:
<# if ((bool)property.GetExtensiblePropertyValue("Identifier"))
{
#> [System.ComponentModel.DataAnnotations.Key]
<# }
#>
And now finally to the most complicated part: the connections between Persistent Objects. At first glance the code we’re going to write seems redundant, but a Persistent Object can be the source or the target of an association, depending on how the association was created using the Persistent Object Model designer. That’s why we’re going to need two loops here – one for where the persistent object is the source, and one where the persistent object is the target of the association.
Then we need to decide if it’s a collection property (e.g. a bank managing a collection of accounts) or a single reference (e.g. a cash card belonging to only one customer).
Here is how it works for associations where the persistent object is the source. Place this code at // 2: create associations
// 2: create associations
<# foreach (tasl.Dsl.PersistentRelation relation in
persistentObject.Sources.TargetDomainRole.GetElementLinks(persistentObject))
{
if (relation.Source.Name == persistentObject.Name)
{
if (relation.TargetMultiplicity == tasl.Dsl.Multiplicity.ZeroMany)
{
// this is a collection property
#> private ObservableCollection<<#= relation.Target.Name #>>
_<#= relation.TargetRoleName #>
= new ObservableCollection<<#= relation.Target.Name #>>();
public ObservableCollection<<#= relation.Target.Name #>>
<#= relation.TargetRoleName #>
{
get
{
return _<#= relation.TargetRoleName #>;
}
set
{
_<#= relation.TargetRoleName #> = value;
OnPropertyChanged("<#= relation.TargetRoleName #>");
}
}
<# }
else
{
// this is a reference property
#> private <#= relation.Target.Name #> _<#= relation.TargetRoleName #>;
public <#= relation.Target.Name #> <#= relation.TargetRoleName #>
{
get
{
return _<#= relation.TargetRoleName #>;
}
set
{
_<#= relation.TargetRoleName #> = value;
OnPropertyChanged("<#= relation.TargetRoleName #>");
}
}
<# }
}
}
#> // 5: create target associations here
And now finally for those associations where the current persistent object is the target. This code should be placed at “// 5: create target associations here”:
<# foreach (tasl.Dsl.PersistentRelation relation in
persistentObject.Targets.TargetDomainRole.GetElementLinks(persistentObject))
{
if (relation.Target.Name == persistentObject.Name)
{
if (relation.SourceMultiplicity == tasl.Dsl.Multiplicity.ZeroMany)
{
// this is a collection property
#> private ObservableCollection<<#= relation.Source.Name #>>
_<#= relation.SourceRoleName #>
= new ObservableCollection<<#= relation.Source.Name #>>();
public ObservableCollection<<#= relation.Source.Name #>>
<#= relation.SourceRoleName #>
{
get
{
return _<#= relation.SourceRoleName #>;
}
set
{
_<#= relation.SourceRoleName #> = value;
OnPropertyChanged("<#= relation.SourceRoleName #>");
}
}
<# }
else
{
// this is a reference property
#> private <#= relation.Source.Name #> _<#= relation.SourceRoleName #>;
public <#= relation.Source.Name #> <#= relation.SourceRoleName #>
{
get
{
return _<#= relation.SourceRoleName #>;
}
set
{
_<#= relation.SourceRoleName #> = value;
OnPropertyChanged("<#= relation.SourceRoleName #>");
}
}
<#
}
}
}
#>
This completes the T4 template that generates C# code classes from the Persistent Object Model created in the second part of this blog series. The T4 template generated in this part can be reused for other Persistent Object Models as long as they provide an extensible property “Identifier” for Model Properties.
Continuation
In the upcoming parts of this blog series we are going to use the code generated by this T4 Template to create a data persistence layer using a relational database. Based on the Persistent Object Model we’re going to create some basic UI for displaying and interacting with the domain specific data objects.