Knowledge is power. We love to share it.

News related to Mono products, services and latest developments in our community.

mario

T4 templates in Entity Framework 4

08/04/2011
Introduction to T4 text templates

T4 templates have been available since Visual Studio 2005, but in VS 2010 templates are much easier to use because they are preprocessed. T4 text templates have ASP.NET-like syntax and allow us to generate any kind of text using custom logic to fine tune the code generation process. We can generate classes, tests, configurations and other file types.
Generating code at design time allow users to strongly typed code that is very easy to use. Code can be generated on any type of model (UML, DSL, etc.). Generated code saves time, frees us from doing repetitive coding tasks and allow us to focus on the business logic. Visual Studio 2010 can be the only thing you need for creating and editing T4 templates, but for the purposes of this article I decided to investigate a bit and found a few products with full Intellisense and syntax highlighting support. Tangible Engineering offers two versions of their editor - Free and Pro editions. I wanted to use the free edition but it turned out that it has limited Intellisense support so I ended up using Visual T4 from Clarius Consulting. VisualT4 is available for download from Visual Studio Gallery (it was in beta as of 6/9/2011). It has full Intellisense support and works like a charm.

EF4 DbContext meets Repository and UnitOfWork patterns

Let's start by showing how to generate simple implementations of Repository and UnitOfWork patterns for EF4 DbContext. While DbContext in Entity Framework 4.1 comes with a lot of builtin functionality, there are some things which needs to be manually coded and I wanted to save time making T4 templates do the grunt work.
For more general info on Entity Framework please visit the ADO.NET blog.

Setting up a project

1. Before we start, if you don't have it, please to download and install ADO.NET Entity Framework 4.1 (or "Magic Unicorn Edition" as baptised by Scot Hanselman) and Entity Framework 4.2 June 2011 CTP. CTP version includes ADO.NET DbContext Generator v4.2. which we will use in this tutorial.
2. Download and install Visual T4 editor.
3. Create new Visual Studio solution with class library project in it.
4. Add a reference to EF 4.1 (EntityFramework.dll)
5. We use the Model First approach introduced in Entity Framework 4, so please add ADO.NET Entity Data Model to project and create an empty model. Set Code generation strategy to None to avoid generating duplicate classes because we will use non-default templates for our classes. Also, set Pluralize New Objects to True.






6.
Create classes for our model.


7. Add ADO.NET DbContext Generator V4.2 and replace $edmxInputFile$ with SampleModel.edmx to generate classes for our model. This will add two templates, one for the POCO objects, and the other for the Model Context.


8. Right click on the model space and choose Generate Database from Model... Create a new database by setting connection values.
9. After VS creates our script run it on a newly created database
10. In this step we will make an interface and the accompanying implementation for our context. After we added the DbContext templates, VS generated DbContext for us with a SampleModelContainer class. Now we need to extend that container with our implementation of the UnitOfWork pattern. Proceed by creating the IUnitOfWork interface with Commit member 
using System;
using
System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
 
namespace SampleRepository
{
    public interface IUnitOfWork
    {
        int Commit();
    }
}

...and create a SampleModelContainer partial class with the concrete implementation of IUnitOfWork.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SampleRepository
{
    public partial class SampleModelContainer : IUnitOfWork
    {
        /// <summary>
        /// Commit changes to database.
        /// </summary>
        /// <returns></returns>
        public int Commit()
        {
            return this.SaveChanges();
        }
    }
}


Creating a template

We will now add a TextTemplate item to our project. Make sure that a Custom tool property for this template is set to TextTemplatingFilleGenerator, which will instruct VS to run generation after every change. You may run generation of code by clicking on Run custom tool option from the context menu on any template.


It is recommended to keep all code not directly related to the generated file in codebehind files. This way, even large templates will be easier to maintain and read. Our example is very simple template and, for the sake of simplicity, we didn't use this approach.
Now, template header defines a template language, include files, assemblies, namespaces and the output extensione. We included EF.Utility.CS.ttinclude file for easier browsing of our model.
<#@ template language="C#" debug="true" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ Assembly Name="System.Windows.Forms" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ Import Namespace="System.Windows.Forms" #>
<#@ output extension=".cs"#>

After setting the name of the file, we will use CodeGenerationTools for creating namespace in our class, EdmItemCollection for organizing repository entities, and the file manager to create output files.
<#
 
// This needs to be set to the .edmx file that you want to process.
string edmxFile = @"SampleModel.edmx";
 
CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
MetadataTools tools = new MetadataTools(this);
EdmItemCollection designerObjects = loader.CreateEdmItemCollection(edmxFile);
EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);

In next part of our template we will create files with code for our repositories for the each entity in the model. This is a partial code - a complete solution is attached to this article:
string types = String.Empty;
foreach (var item in designerObjects.GetItems<EntityType>())
{
    fileManager.StartNewFile(GetFileName(item.Name));
#>
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
 
namespace <#= code.VsNamespaceSuggestion() #>
{
 
    public class <#= item.Name #>Repository : IDisposable
    {
        private DbContext _context;
 
        #region Constructor
        /// <summary>
        /// Hide this constructor from use.
        /// </summary>
        private <#= item.Name #>Repository()
        {
        }
 
        /// <summary>
        /// Add new entity.
        /// </summary>
        /// <param name="entity"><#= item.Name #> entity</param>
        public void Add(<#= item.Name #> entity)
        {
            _context.Set<<#= item.Name #>>().Add(entity);
        }
 
        public void Dispose()
        {
            _context.Dispose();
        }
    }
 
}
<#
}
    fileManager.Process();
#>
 
We will put a helper method to get file name for each class at the end of a template:
<#+
    private string GetFileName(string entityName)
    {
        return String.Format(@"{0}Repository.cs", entityName);
    }
#>

We are now ready to compile the project and use the generated classes.
Here is a sample code that illustrates how to use the generated classes. I included a few tests in the attached solutions to make sure that everything works as it should. You will also find samples on how to use these classes in other scenarios.
public Document InsertNew()
{
    using (var uow = new SampleModelContainer())
    {
        var repDoc = new DocumentRepository(uow);
        var repDocItem = new DocumentItemRepository(uow);
 
        var document = new Document();
        var item1 = new DocumentItem();
        var item2 = new DocumentItem();
        repDoc.Add(document);
 
        return document;
    }
}

Rated 3.00, 2 vote(s).