
Earlier I displayed a neat trick to keep track of modification and creation data with ADO.NET entity framework for .NET Framework 4. I quickly discovered there’s a new feature in .NET 4 to simplify things even more.
Visual Studio 2010 enables the use of T4 templates to customize the logic used to generate the entity classes and the object context. In this post I will explain how it works and what you will need to modify in the templates to get the results of my previous blogpost on this subject.
A word of warning in advance: While T4 templates are very powerful it’s kind of difficult to work with them. This post assumes that you are either a .NET daredevil or know what you are doing. Otherwise I recommend that you download the completed template at the end of this post.
Enabling the T4 template
To enable the use of T4 template you can right click on the model in Visual Studio 2010 and select Add code generation item.
This will open up a new dialog with the option to select one of the code generation templates to use for the new code generation item. If you select the item code on the left-hand side of the screen, you will be able to select ADO.NET Entity object generator as the template for the new item. Give the new item a descriptive name and press the accept the settings for the dialog.
Creating a new T4 code generation item for the datamodel will disable the default code generation and use the added template instead. Once the template is executed by Visual Studio 2010 it will create a new C# file (or VB.NET file if you’re into that) for you as a child of the T4 template. This file will contain the same code as before.
Customizing the T4 template to generate ITrackableEntity
Before we can start modifying the template to generate entities that implement ITrackableEntity we will need to create the ITrackableEntity interface. For this I’ve created the following snippet of T4 logic.
1: <#
2: region.Begin("Trackable entity logic");
3: #>
4:
5: public interface ITrackableEntity
6: {
7: string CreatedBy { get; set; }
8: string ModifiedBy { get; set; }
9: DateTime? DateModified { get; set; }
10: DateTime DateCreated { get; set; }
11: }
12:
13: <#
14: region.End();
15: #>
You can add this snippet somewhere around line 335 of the standard template. Just before the template reads “//////// Write EntityType classes. “ This will create a new #region directive and within that directive add the ITrackableEntity interface.
Note: When you edit the T4 template from Visual Studio 2010 you will notice that there’s no intellisense. Combined with the fact that the template is a complete mess there’s no way that you will be able to make modifications fast. To alleviate some of the pain I can recommend the Clarius Visual T4 editor.
Using ITrackableEntity in every generated entity
Right after where the template reads “//////// Write EntityType classes. “ the entities are generated. Originally the template will generate classes that derive from EntityObject. To make each entity trackable we will need to modify the template so that it generates ITrackableEntity.
The following snippet does just that:
1: <#
2: ////////
3: //////// Write EntityType classes.
4: ////////
5: region.Begin(GetResourceString("Template_RegionEntities"));
6: foreach (EntityType entity in GetSourceSchemaTypes<EntityType>().OrderBy(e => e.Name))
7: {
8: #>
9: /// <summary>
10: /// <#=SummaryComment(entity)#>
11: /// </summary><#=LongDescriptionCommentElement(entity, region.CurrentIndentLevel)#>
12: [EdmEntityTypeAttribute(NamespaceName="<#=entity.NamespaceName#>", Name="<#=entity.Name#>")]
13: [Serializable()]
14: [DataContractAttribute(IsReference=true)]
15: <#
16: foreach (EntityType subType in ItemCollection.GetItems<EntityType>().Where(b => b.BaseType == entity))
17: {
18: #>
19: [KnownTypeAttribute(typeof(<#=MultiSchemaEscape(subType, code)#>))]
20: <#
21: }
22: #>
23: <#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#> : <#=BaseTypeName(entity, code)#>, ITrackableEntity
It will loop through each of the entities found in the EDMX file and generate a new class for it. I’ve modified this code to append ITrackableEntity to the list of base types the class implements/inherits from.
Customizing the logic generated for the ObjectContext
Running the template now will generate an object context, the ITrackableEntity interface and the entities from the data model. The last step is to extend the logic generated for the ObjectContext in the data model so that it includes the logic required to keep track of the creation and modification data.
For this I appended the following T4 code to the section of the T4 template that takes care of generating the object context.
1: <# region.Begin("Save changes override") #>
2: public override int SaveChanges(SaveOptions options)
3: {
4: foreach (var entry in ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added))
5: {
6: var trackable = entry as ITrackableEntity;
7: if (trackable != null)
8: {
9: trackable.DateCreated = DateTime.Now;
10: trackable.CreatedBy = System.Threading.Thread.CurrentPrincipal.Identity.Name;
11: }
12: }
13:
14: foreach (var entry in ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified))
15: {
16: var trackable = entry as ITrackableEntity;
17: if (trackable != null)
18: {
19: trackable.DateModified = DateTime.Now;
20: trackable.ModifiedBy = System.Threading.Thread.CurrentPrincipal.Identity.Name;
21: }
22: }
23:
24: return base.SaveChanges(options);
25: }
26: <# region.End(); #>
27: }
28: <#
29: }
30: region.End();
31: #>
Running the template
The final step is to save the changes to the T4 template. Each time you change the template and save it, the template will be executed automatically. Before Visual Studio 2010 is going to execute the template however it will ask for a confirmation that you are OK with that.
The template will also be executed when the EDMX file is changed. This ensures that you will always have the latest version of the generated code when you either change the template or the data model.
Conclusion
The new implementation of ADO.NET entity framework in .NET Framework 4 is very powerful. Microsoft has put in a ton of changes to make the framework a lot better than the first version that came with .NET 3.5 SP1.
It’s funny that they didn’t come up with the T4 template extensions, because T4 has been around since Visual Studio 2005. Microsoft uses it internally to build templates for various frameworks that are plugged into Visual Studio. I’m glad however that they expose these now, because that enables us developers to make life a lot easier when it comes to exposing database models inside our web services and what-not.
The download for the fully modified T4 template is attached to this blogpost.