By: Corey Adler, Staff Developer
Microsoft’s Text Template Transformation Toolkit (or T4 for short) is a wonderful tool that can help developers automatically generate code or text files that would have taken hours to do manually in just a few short minutes. It’s used in many different places for many different reasons. In this post I’ll show you how using T4 can bring you much joy with Entity Framework, specifically with using it to generate a DbContext while in Code First with Data Annotations. It is theoretically possible to do so also with the Fluent API, but that would certainly take much longer than is actually necessary.
So how do I make them interact? First, before you start you should do one of two things:
1) Preferably, you should decide to place all of your entity classes in their own project. This will provide you with the terrific benefit of separation of concerns, as well as clean code.
2) If, for some reason, it would be impossible to do #1 (such as working on a legacy product), then you should create a blank interface that all of your domain entities should implement, which I will call IDomainEntity.
After you’ve made sure to set all of that up, it’s time to start our T4 template! First, as always with T4, comes the setup and references.
Two things to note: It’s important to bring in the assembly for your domain entities, primarily because we will be doing reflection on it later on in the T4 file. Second, notice the 2 variables at the bottom called “left” and “right”. Those are absolutely vital to doing this, because the left and right brackets are actually reserved as T4 commands, and so you can’t use them in the rest of the file for generating a generic DbSet (as you’ll see later).
Once we’ve done that it’s time to start generating some code! Make sure that you place the using statements for all of the namespaces (and for Entity Framework!), as well as start the file like a normal C# file. Believe me; I’ve had my fair share of forgetting to do this while I’ve been working with T4!
That’s simple enough so far, right? Now is when we get our hands dirty with T4. Here is the main part of the code:
The first thing you should notice is just how messy it looks. One of the big challenges when working with T4 is getting your output to look just right. The way it looks above comes out nice and clean looking on the other end. The reason this happens is because anything that happens outside of the actual T4 code (i.e. what’s going to be printed on the screen) is outputted—including whitespace and carriage returns!
The steps I’ve done above are fairly simple: 1) Grab the assembly with the domain entities. 2) Grab all of the domain entities from the assembly. 3) Have T4 output DbSet<> properties for each of those types. One stylistic point that I should mention before showing my code is the fact that traditionally in a DbContext class one pluralizes the class name. To do so in my T4 code I have set out 3 possible cases: A) If the class name ends in ‘s’ or ‘h’ put an ‘es’ at the end. B) If it ends with a ‘y’, remove the y and substitute ‘ies’. C) Otherwise just slap an ‘s’ on the end. It’s not perfect, but it will work with most class names that come along. If you want to have other conditions, you can certainly do so, as well as adjust the names of your DbSets (like if you want to put a prefix or a suffix on it).
Afterwards, just make sure to output the correct amount of curly braces, and you should be all set. The finished product speaks for itself:
Two final tips that I should mention before I finish: 1) Be sure that anything you adjust/add (such as overriding the OnModelCreating method of DbContext) is placed into the T4 code. You can start by doing it in C# (to take advantage of Intellisense), but make sure that it goes into the T4 afterwards. Otherwise, you’re liable to lose it. 2) Any adding/deleting of domain entities won’t get populated right away. The first thing you need to do is build the domain entities’ project (so that the DLL file will be properly updated), and only then run the transformation. Otherwise, you’ll get your fair share of build errors. T4 is a wonderful tool that can be used in a wide variety of situations, but can have a steep learning curve. I’ll hopefully tackle some other T4 aided solutions in future posts. Until then, I wish you good coding.