Automatically Generate Code Using Visual Studio's Text Template Transformation Toolkit (T4)
 
Published: 24 May 2011
Unedited - Community Contributed
Abstract
Visual Studio has built in support for generating code called the Text Template Transformation Toolkit. This article will demostrate how to create a class with a property for each column in a database table. The sample can easily be extended to fit any pattern you use when developing applications.
by Vince Varallo
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 30003/ 35

Introduction

How many times have you found yourself creating a class that has a property for each field in a table, or creating select, insert, update, and delete stored procedures for each table in a database?  As a developer even we are subject to such mundane tasks which, as a developer, we are supposed to automate.  Did you know that Visual Studio has a built in toolkit which will allow you to automatically generate code for these tasks and it is free?  If you've installed Visual Studio then you already have it.  It's called the Text Template Transformation Toolkit (T4) and it works right within Visual Studio.

This article will demonstrate how to create a C# class file that is generated by T4.  The class will contain a property for each field in the database.  The example is simple but it will demonstrate the power of the toolkit and you can enhance the code to match the patterns you follow.  The code for the sample can be found here.

The example code uses the AdventureWorks sample database which you can download here.  Once you've installed the database you need to create a SQL Login that the application can use to connect to the database.  My sample code expects a SQL Login to be called "aspalliance" and the password should be set to "aspalliance".

Generating the Code

Step 1: Create the Code Generator Project

1.   Launch Visual Studio 2010.

2.   From the Start page click on the "New Project…" link.

3.   Select Class Library from the list of installed templates.

4.   Name the project CodeGeneratorT4.

5.   Click the OK button.  Visual Studio will create your project and add the Class1.cs file.

6.   Right click on the Class1.cs file in the Solution Explorer and delete this file from the project.

Step 2: Create a Text Template that Creates a Class

1.   Right click on the CodeGeneratorT4 project in the Solution Explorer and select AddàNew Item… from the pop-up menu.

2.   Select Text Template from the list of installed templates.

3.   Name the file BusinesObject.tt and click the Add button.

4.   Open the BusinessObject.tt file.  You will get a security warning message from Visual Studio but you should just click the OK button.

5.   There are two lines of code in the file.

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".txt" #>

These blocks of code are called Directives.  A Directive starts "<#@" and tell the text templating engine how to generate the code.  A complete list of directives can be found here.

The "debug" attribute can be set to true or false.  Setting it to true will enable you to debug this template.  The "language" attribute is set to C#.  The language attribute specifies the language that is used in the expression blocks in the template.  You could set this to VB is you prefer to code in Visual Basic.

The second line contains the output directive.  The "extension" attribute is used to specify the file extension for the file that will be created by this template.  Change this setting from ".txt" to ".cs" because we will be creating a C# class file.

6.   In this example we are going to read from a database so we need to use objects in the System.Data and System.XML assemblies.    To reference an assembly you use an assembly directive and set the name attribute to the assembly you want to reference.  Add the following lines of code to the template.

<#@ assembly name="System.Data" #>
<#@ assembly name="System.XML" #>

7.   Once you've referenced your assemblies you need to specify an import directive to use the namespace defined in the assembly.  This is equivalent to the "using" statement in C#.

<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>

8.   The next step is to create a Control Block that executes code to open the database and get a table schema.  Code blocks start and end with <# #>.

<#
   string tableName = "Person.Address";
   string className = "Address";
 
   SqlConnection cn = new SqlConnection("Data Source=(local);User
     ID=aspalliance;Password=aspalliance;Initial Catalog=AdventureWorks;");
   cn.Open();
   SqlCommand cmd = new SqlCommand("SELECT * FROM " + tableName, cn);
   DataTable dt = cmd.ExecuteReader(CommandBehavior.CloseConnection).GetSchemaTable();
#>

The sample code here creates a variable called tableName which is used to specify the table in the database that you want to map.  In this instance the table name is Person.Address.  Since we don't want the class name to be Person.Address I created a second variable so you can specify a class name.  If you wanted to map a different table you could easily just change these two variables.

The next few lines use standard C# code to open a database and load the schema for a table.  One bad thing about using T4 templates is that you don't get intellisense, so you have to make sure you spell everything correctly and use the correct case.

If you save the file you will see any complier errors in the Error window.  Fix any errors before moving to the next step.  Saving actually runs your code through the T4 engine and will generate the file for you.  You don't use the play button (F5) like a regular project.

9.   The next step is to create Text blocks which will contain the using statements for the file we are going to generate.  Enter the following statements in your template.  Remember, these lines of code will be echoed exactly as they are written to the output file because they are not contained between any <# tags.

using System;
using System.Data.SqlClient;
using System.Data;

10. Now save your file again.  Whenever you save the template will try to generate the output file. If you look in your Solution Explorer you should see a file underneath the BusinessObjects.tt file.

If you open this file you'll see that the using statements from your Text Block are generated in this file.

11. Now we'll write the code to declare our class.  Remember that our class is going to be named whatever value you set the className variable to.

public class <#= className #>
 

The <#= syntax signifies an Expression control block.  An Expression control block will be evaluated and automatically converted into a string by the engine.  Notice that I'm using the className variable that was defined in the previous code block.  If you save now you should see the following output.

12. Now let's build the rest of the class.  This example will generate a property for each field in the table. Add the following code.

{
<# 
   foreach(DataRow dr in dt.Rows)
   {
       Write("    public " + dr["ColumnName"+ " { get; set; }" +
             Environment.NewLine); 
   }
#>
}

The first open curly bracket is for the class and is a text block.  The second line starts a control block which loops around each row in the DataTable and creates a public property for each column.  Notice I'm using the "Write()" method which you can use to control what gets written to the output file.  If you save your file you should see the following output.

using System;
using System.Data.SqlClient;
using System.Data;
 
public class Address
{
    public AddressID { get; set; }
    public AddressLine1 { get; set; }
    public AddressLine2 { get; set; }
    public City { get; set; }
    public StateProvinceID { get; set; }
    public PostalCode { get; set; }
    public rowguid { get; set; }
    public ModifiedDate { get; set; }
}

Notice the bug here.  I didn't specify the data type for the property. I'm going to create a Class Feature Block which is what you use to create functions within your template.  A class feature block starts with <#+ and must be placed at the end of the file they are in.  The function I create will look at the SQL data type and convert it to the C# equivalent.

<#+
private string GetCSharpType(DataRow dr)
{
      bool isNullable = Convert.ToBoolean(dr["AllowDBNull"]);
 
      switch (dr["DataType"].ToString())
      {
            case "System.Int16":
                  if (isNullable)
                        return "Nullable<short>";         
                  else
                        return "short";
 
            case "System.Int32":
                  if (isNullable)
                        return "Nullable<int>";
                  else
                        return "int";
 
            case "System.String":
                  return "string";
 
            case "System.DateTime":
                  return "DateTime";
 
            case "System.Byte":
                  if (isNullable)
                        return "Nullable<byte>";
                  else
                        return "byte";
 
            case "System.Byte[]":
                  return "Binary";
 
            case "System.Boolean":
                  return "bool";
 
            case "System.Decimal":
                  return "double";
 
            case "System.Guid":
                  return "Guid";
 
            default:
                  throw new Exception("Type not known");
      }
}
#>

13. Now that the GetCSharpType function is in place we can call it when creating the property.  Change the line to the following.

Write("    public " + GetCSharpType(dr) + " " + dr["ColumnName"+ " { get; set; }" + Environment.NewLine);
 

14. Now save your template and your class file should be created.

 

Your template file should look like the following image.

 

Summary

This sample used the basic functionality of the T4 engine but as you can see it can be quite powerful.  You can create templates for you business classes, data classes, even your aspx and code behind pages.  It takes some time to get used to the syntax but once you get the hang of it it's fairly simple.  It reminds me of the old style of coding classic asp pages where you mixed your HTML markup and code in one file.  Feel free to take the sample code and extend it for you projects.

Good luck on your project and happy coding. 



User Comments

Title: nfl jerseys cheap   
Name: NIKE NFL jerseys
Date: 2012-07-02 10:12:01 AM
Comment:
http://www.jersey2shop.com
http://www.cheapjersey2store.com
http://www.jerseycaptain.com
http://www.yourjerseyhome.com
We are professional jerseys manufacturer from china,wholesal.cheap nike nfl jerseys, mlb jerseys, nhl jerseys,nba jerseys and shoes
Cheap NFL,NBA,MLB,NHL
,heap jerseys,2012 nike nfl Jerseys,nba jersey and shorts,oklahoma city thunder jersey,official jeremy lin new york knicks jersey,NFL Jerseys Wholesale,blake griffin jersey blue,NFL jerseys For Sale online.All Our Jerseys Are Sewn On and Directly From Chinese Jerseys Factory
,Wholesale cheap jerseys,Cheap mlb jerseys,]Nike NFL Jerseys,Cheap China Wholesae,Wholesale jerseys From China,2012 nike nfl Jerseys,Jerseys From China,,2012 nike nfl Jerseys,Revolution 30 nba jerseys,jersey of nba chicago bulls direk rose ,nfl jerseys,green bay packers jerseys wholesale,Buffalo Bills nike nfl jerseys sale,good supplier soccer jerseys,cool base mlb jerseys,Revolution 30 nba jerseys,2012 stanley cup nhl jersey,
We are professional jerseys manufacturer from china,wholesal.cheap nike nfl jerseys, mlb jerseys, nhl jerseys,nba jerseys and shoes. www.yourjerseyhome.com
Title: External   
Name: Manikandan Ganesan
Date: 2011-06-19 6:26:51 PM
Comment:
Hi,

I used to create Project and Item templates before start any project and that helps me a lot. This is useful information and thanks for posting.

Thanks,
Mani
Title: External   
Name: Pyrros
Date: 2011-06-10 12:54:06 PM
Comment:
How can we use this template to generate code outside this project (from another project)? Something like Add>New Item… and select the template above?
Title: mr   
Name: henry
Date: 2011-05-25 6:28:02 AM
Comment:
Nice one. Pls can u modify it to iclude a method to insert to the able
Title: Mr.   
Name: Ranjan
Date: 2011-05-25 4:37:19 AM
Comment:
A very good and useful thing i have found in this article for my project. Many times we work on the project which is n-tier architecture and coding for business layer is little time taking to create classes for each and every table of database in our project. So it makes it easy for developer to save their time.
Title: Mr.   
Name: S Krupa Shankar
Date: 2011-05-24 10:40:54 PM
Comment:
A very good, short and crisp introduction.

And should it be dt.Columns instead of dt.Rows?

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-28 8:33:53 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search