T4 Templates Part Duex

by jmorris 15. December 2010 23:04

I previously wrote about some experiences I have had with T4 templates and generating objects from database tables using the MSSQL metadata tables. Well another code generation opportunity came up and a comment by a reader pointed me in the direction of Damian Guard’s Manager.tt template so I decided to take a look. Nothing wrong with using something better than what you’ve already developed.

First up, a couple of observations with T4 and VS2010 (my previous experience with T4 in my post was using VS2008 and it would interesting to see how far T4 and IDE have come along).

“Save” Means “Execute”…Still!

The first thing I have noticed, which I was hoping would have changed, was the generation model/compilation model: when ever you hit Ctrl S, the template will save and immediately be run by the T4 engine. The problem with this is that if your doing a bunch of refactoring and if your work flow is modify/save/build (such as mine is, I blame TDD) then you’ll quickly slow down as the code generated that doesn’t compile will muck up VS. For example if you are generating a lot of files, things slow down to a stop if this happens after every save. I think it would be so much nicer if it was tied into it’s own command (such as in the Build dropdown) and instead of piggy-backing on “Save”.

Always Set debug=true!

This is super important -- always set debug to “true” on your template headers:

image

Doing this is the difference between pulling your hair out trying to figure what is failing and quickly fixing the issue and moving along

Assembly Locking is Major PITA: Use VolatileAssembly Directive from the T4 Toolbox!

Note: Apparently this is resolved in VS2010 SP1 (Thanks Will!)

One thing that you’ll quickly discover if your calling into code that exists outside of the template (such as the assembly that you are creating your templates in) is that the T4 engine will reuse the assemblies used by the templates, thus they will remain blocked while the engine is running. What this means is that you will have to close VS and reopen it if you want to modify the code in those assemblies (such as when you discover an issue in the code the template is using to generate your output).

Closing and Reopening Visual Studio is a major PITA and seriously cuts into your productivity. Fortunately, there is a workaround: download and install the T4 Toolbox from CodePlex.com and use the VolatileAssembly directive on one and only one template.

image

What this does is create a temporary copy of the referenced assembly for each template generation which is cleaned up after the generation completes.

Damien Guards Manager.tt Template Rocks!

Now for the grand finale: Damien Guards Manager.tt is awesome and really makes multi-file code generation easy. For details, check out his blog posting from the references below, but here is quick overview:

image

Here is a breakdown of what is going on:

  1. Include Damien’s Manager.tt T4 template
  2. Create a reference to the T4 generation environment
  3. Start a new file using StartNewFile(string fileName). The file’s body is created between this method call and the next EndBlock()
  4. EndBlock() stops the generation of the file’s body
  5. StartHeader() starts a new header section
  6. EndBlock() ends the header section
  7. Call Process() to generate the files

It’s really pretty straightforward and easy to use.

References

Tags: , , ,

T4

Generating Data Transfer Objects with Seperate Files from a Schema Using T4

by jmorris 3. December 2009 04:21

T4, or Text Template Transformation Toolkit, is a template based solution for generating code that is built into VS2008 (it's also available as an add in VS2005). Alas, it has minimum support in VS2008 in that there are are no Visual Studio Template for adding a T4 template - you cannot just right click Add > New Item and add a T4 file to you project. However, you can create a new file and change the extension to ".tt" and VS will know that you are adding a T4 file to the project (after a security prompt asking you if you want to really add a T4 file) and create the appropriate T4 template and .cs code behind file that accompanies each .tt file. For a detailed explaination of how to do this, please see Hanselman's post here.

T4 templates are pretty cool once you get the hang of some of nuances of the editor, which is somewhat lacking in features (reminds me of using Notepad to write Assembly code in college). There are in fact at least two VS add ons that add some degree of intellisense and code/syntax highlighting: Clarius Visual T4 and Tangible T4 Editor for VS. They both offer free developer editions with limited functionality if you just want to get a feel for what they can do without forking out the cash.

Out of the box, T4 templates have one glareing weakness: only one template (.tt) file can be associated with one output file (.cs, et al). This is not really ideal in that we typically associate one source code artifact (class, sproc, etc) with it's own file. This makes it easier to grok, manage, read a projects source and also makes versioning easier using version control software such as Git or Subversion. It's much easier to track changes to a single class in a file than multiple classes in a file. With a little work and a little help it is possible to generate multiple source files from template files, however.

So, T4 aside, what are Data Transfer Objects (DTOs) and why do need them? DTOs are exactly what they propose to be: objects containg data, typically corresponding to a single record in a database table. In my opinion, they are anemic in that they contain NO behavior whatsoever. They are the data...constrast this with domain objects, which are data and behavior. A very typical scenario involving DTOs are situations where data must be moved from one part of the system, to another where they are consumed and used, likely by a domain object(s). For instance, we may use an ORM such as NHibernate or Entity Framework to access the database, bring back a set of data and then map it a DTO.

In many cases your DTOs are mapped directly to your database schema in that there is a one to one mapping between table and object field or property. In this situation, manually creating an object per entity becomes tedious and scales poorly in terms of developer productivity. This is where using a code generation solution, such as one created with T4 really shines.

For example, given the following schema, generate a DTO for each entity:

The first step is getting enough information about the tables from the database metatables so that you can generate objects for each table. Assuming you are mapping to pure DTOs, you can ignore any of the relationships in the form of 'Has A' in your objects. It's not these relationships do not exist; they do, just not explictly. Instead you maintain the relationships through properties that represent the foriegn keys between the objects. An obvious benefit to this sort of convention is that you immediatly resolve the potential n+1 problems inherit with ORMs and lazy loading, at the expense some other features of ORMs, such as object tracking. IMO ignoring these relationships is a personal preference as well as a architectural concern; for this example I am ignoring these relations.

The following sproc is an example of how to get this data from a database, in this case I am using MS SQL Server 2008:



This stored procedure returns a record describing the table and each column of the table or at least the relevent parts: name, data type, and whether or not the column is a primary key. This sproc is called from a T4 template to load a description of each table and it's columns into memory. Here is the relevent code:



In order to generate seperate files for each artifact generated, we will be using three seperate T4 templates: GenerateEntities.tt, Entity.tt, and MultiOuput.tt. GenerateEntities.tt contains the code above as well as another code block in which it loops through the results returned from GetTypes() and uses the Entity.tt template to generate the artifact. The MultiOuput.tt takes the code generated by GenerateEntities.tt and Entity.tt to write the output file to disk and add the file Visual Studio. Note that MultiOutput.tt comes from one of many excellant posts by Oleg Sych and that an updated version of the file is purported to be available with the T4 Toolkit up on CodePlex.com.




The code above loops through the table definitions and uses remoting to set a property on the Entity.tt template with each value. Finally, the MultiOutput.tt.ProcessTemplate(...) method is called which writes the output of Entity.tt to disk and adds the file to Visual Studio. Entity.tt is pretty straight forward:



When the solution is saved, the T4 templating engine will process the templates a file will be added to Visual Studio under the GenerateEntities.tt file that represents a DTO for each table in the database.



References:

  1. http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
  2. http://www.codeplex.com/t4toolbox
  3. http://www.olegsych.com/2008/03/how-to-generate-multiple-outputs-from-single-t4-template/

Tags: , , , , ,

Jeff Morris

Tag cloud

Month List

Page List