Using T4 Templates to extend your Entity Framework classes

A set of entities I’m using with Entity Framework (I’m using EF POCO) have common properties implying commonality between the entities. I didn’t want to use any form of inheritance within my object model to express this commonality, but I did wish to have the entity classes implement common interfaces. It’s easy to do this because entities are partial classes. Say for example all my entities have a string property UserName, I can define an interface to express this, and then have a partial implemention of the class that implements the interface.

public interface IUserNameStamped
{
    string UserName { get; set; }
}
    
public partial class Entity1 : IUserNameStamped
{
}
    
public partial class Entity2 : IUserNameStamped
{
}

So the POCO T4 template generates the “main” class definition for each entity, with all it’s properties, and then these partial classes extend the class, not adding any new properties or methods, just extending with the fact each class implements the IUserNameStamped interface.

I quickly realised that I could use T4 in a similar manner to the EF POCO T4 template, in order to produce these partial classes automatically.

As I explained in my post about UserName stamping entities as they’re saved, all my entities have a UserName column. So all this template has to do is loop through all the entities in my object model, and write an implementation for each.

The main T4 logic is

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs"#>
<#
string inputFile = @"OticrsEntities.edmx";
EdmItemCollection itemCollection = new MetadataLoader(this).
    CreateEdmItemCollection(inputFile);

CodeGenerationTools code = new CodeGenerationTools(this);
string namespaceName = code.VsNamespaceSuggestion();

WriteHeader();
BeginNamespace(namespaceName, code);
WriteIUserNameStamped();
WriteEntitiesWithInterface(itemCollection);
EndNamespace(namespaceName);
#>

Most of this is cribbed unashamedly from the EF POCO T4 template. Firstly we initialise some variables, the most interesting being itemCollection, which is what allows access to the entity metadata. We then write a header indicate the file is a generated file, start the namespace, write the actual declaration of the IUsernameStamped interface, write a partial class for each entity implementing the interface, and then end the namespace. The specifics of each method are:

<#+
void WriteHeader(params string[] extraUsings)
{
#>
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

<#=String.Join(String.Empty, 
    extraUsings.Select(u => "using " + u + ";" + Environment.NewLine).ToArray())#>
<#+
}

void BeginNamespace(string namespaceName, CodeGenerationTools code)
{
    CodeRegion region = new CodeRegion(this);
    if (!String.IsNullOrEmpty(namespaceName))
    {
#>
namespace <#=code.EscapeNamespace(namespaceName)#>
{
<#+
        PushIndent(CodeRegion.GetIndent(1));
    }
}


void EndNamespace(string namespaceName)
{
    if (!String.IsNullOrEmpty(namespaceName))
    {
        PopIndent();
#>
}
<#+
    }
}

I think these three methods are fairly self-explanatory, other than the <# syntax that T4 uses to indicate code and text blocks.

void WriteIUserNameStamped()
{
#>
/// <summary>
/// An entity that is stamped with the Username that created it
/// </summary>
public interface IUserNameStamped
{
    string UserName { get; set; }
}

<#+
}

Simply generates the interface definition.

void WriteEntitiesWithInterface(EdmItemCollection itemCollection)
{
	foreach (EntityType entity in itemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
	{
		WriteEntityWithInterface(entity.Name);
	}
}

Iterates through the entities.

void WriteEntityWithInterface(string entityName)
{
#>
public partial class <#=entityName#> : IUserNameStamped
{
}

<#+
}

#>

Writes an implementation of the IUserNameStamped interface for each entity.

So you can see it’s fairly simple to use T4 to generate C# code similar to that at the top of this blog post.

I’ve blogged about how I extended this code to make a certain set of entities with common properties implement a common interface

I’ve also blogged about further extending the template to handle multiple interfaces, with one file per interface.

This is the full code of the T4 template:

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs"#>
<#
string inputFile = @"Entities.edmx";
EdmItemCollection itemCollection = new MetadataLoader(this).CreateEdmItemCollection(inputFile);

CodeGenerationTools code = new CodeGenerationTools(this);
string namespaceName = code.VsNamespaceSuggestion();

WriteHeader();
BeginNamespace(namespaceName, code);
WriteIUserNameStamped();
WriteEntitiesWithInterface(itemCollection);
EndNamespace(namespaceName);
#>
<#+
void WriteHeader(params string[] extraUsings)
{
#>
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

<#=String.Join(String.Empty, extraUsings.Select(u => "using " + u + ";" + Environment.NewLine).ToArray())#>
<#+
}

void BeginNamespace(string namespaceName, CodeGenerationTools code)
{
    CodeRegion region = new CodeRegion(this);
    if (!String.IsNullOrEmpty(namespaceName))
    {
#>
namespace <#=code.EscapeNamespace(namespaceName)#>
{
<#+
        PushIndent(CodeRegion.GetIndent(1));
    }
}


void EndNamespace(string namespaceName)
{
    if (!String.IsNullOrEmpty(namespaceName))
    {
        PopIndent();
#>
}
<#+
    }
}

void WriteIUserNameStamped()
{
#>
/// <summary>
/// An entity that is stamped with the Username that created it
/// </summary>
public interface IUserNameStamped
{
    string UserName { get; set; }
}

<#+
}

void WriteEntitiesWithInterface(EdmItemCollection itemCollection)
{
	foreach (EntityType entity in itemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
	{
		WriteEntityWithInterface(entity.Name);
	}
}

void WriteEntityWithInterface(string entityName)
{
#>
public partial class <#=entityName#> : IUserNameStamped
{
}

<#+
}

#>

Published by

Sam Stephens

Experienced software development engineer, passionate about OO patterns, tidy modular code, and understanding the various tensions and contradictions that are involved in navigating life as a business developer, and delivering superior quality results. Contact me.

2 thoughts on “Using T4 Templates to extend your Entity Framework classes”

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>