Category Archives: Visual Studio

Support for Store Functions (TVFs and Stored Procs) in Code First (Entity Framework 6.1)

See what’s new in Beta here

Until Entity Framework 6.1 was released store functions (i.e. Table Valued Functions and Stored Procedures) could be used in EF only when doing Database First. There were some workarounds which made it possible to invoke store functions in Code First apps but you still could not use TVFs in Linq queries which was one of the biggest limitations. In EF 6.1 the mapping API was made public which (along with some additional tweaks) made it possible to use store functions in your Code First apps. Note, that it does not mean that things will start working automagically once you upgrade to EF6.1. Rather, it means that it is now possible to help EF realize that it actually is capable of handling store functions even when Code First approach is being used. Sounds exciting doesn’t it? So, probably the question you have is:

How do I do that?

To understand how store functions could be enabled for Code First in EF 6.1 let’s take a look first at how they work in the Database First scenario. In Database First you define methods that are driving the execution of store functions in your context class (typically these methods are generated for you when you create a model from the database). You use these methods in your app by calling them directly or, in case of TVFs, in LINQ queries. One thing that is worth mentioning is that these methods need to follow certain conventions otherwise EF won’t be able to use them. Apart from methods defined in your context class store functions must also be specified in the artifacts describing the model – SSDL, CSDL and MSL (think: edmx). At runtime these artifacts are loaded to MetadataWorkspace object which contains all the information about the model.
In Code First the model is being built from the code when the application starts. Types are discovered using reflection and are configured with fluent API in the OnModelCreating method, attributes and/or conventions. The model is then loaded to the MetadataWorkspace (similarly to what happens in the Database First approach) and once this is done both – Code First and Database First operate in the same way. Note that the model becomes read-only after it has been loaded the MetadataWorkspace.
Because Database First and Code First converge at the MetadataWorkspace level enabling discovery of store functions in Code First along with additional model configuration should suffice to add general support for store functions in Code First. Model configuration (and therefore store function discovery) has to happen before the model is loaded to the MetadataWorkspace otherwise the metadata will be sealed and it will be impossible to tweak the model. There are three ways we can configure the model in Code First – configuration attributes, fluent API and conventions. Attributes are not rich enough to configure store functions. Fluent API does not have access to mapping. This leaves conventions. Indeed a custom model convention seems ideal – it gives you access to the model which in EF 6.1 not only contains conceptual and store models but also modifiable mapping information. So, we could create a convention which discovers methods using reflection, then configures store and conceptual models accordingly and defines the mapping. Methods mapped to store functions will have to meet some specific requirements imposed by Entity Framework. The requirements for methods mapped to table valued functions are the following:

  • return type must be an IQueryable<T> where T is a type for which a corresponding EDM type exists – i.e. is either a primitive type that is supported by EF (for instance int is fine while uint won’t work) or a non-primitive type (enum/complex type/entity type) that has been configured (either implicitly or explicitly) in your model
  • method parameters must be of scalar (i.e. primitive or enum) types mappable to EF types
  • methods must have the DbFunctionAttribute whose the first argument is the conceptual container name and the second argument is the function name. The container name is typically the name of the DbContext derived class however if you are unsure you can use the following code snippet to get the name:
        ((IObjectContextAdapter) ctx).ObjectContext.MetadataWorkspace
  • the name of the method, the value of the DbFunction.FunctionName and the queryString name passed to the CreateQuery call must all be the same
  • in some cases TVF mapping may require additional details – a column name and/or the name of the database schema. You can specify them using the DbFunctionDetailsAttribute. The column name is required if the method is mapped to a TVF that returns a collection of primitive values. This is needed because EF requires providing the name of the column containing the values and there is no way of inferring this information from the code and therefore it has to be provided externally by setting the ResultColumnName property of the DbFunctionDetails attribute to the name of the column returned by the function. The database schema name needs to be specified if the schema of the TVF being mapped is different from the default schema name passed to the convention constructor and can be done by setting the DatabaseSchema property of the DbFunctionDetailsAttribute.

The requirements for methods mapped to stored procedures are less demanding and are the following:

  • the return type has to be ObjectResult<T> where T, similarly to TVFs, is a type that can be mapped to an EDM type
  • you can also specify the name of the database schema if it is different from the default name by setting the DatabaseSchema property of the DbFunctionDetailsAttribute. (Because of how the result mapping works for stored procedures setting the ResultColumnName property has no effect)

The above requirements were mostly about method signatures but the bodies of the methods are important too. For TVFs you create a query using the ObjectContext.CreateQuery method while stored procedures just use ObjectContext.ExecuteFunction method. Below you can find examples for both TVFs and stored procedures (also notice how parameters passed to store functions are created). In addition the methods need to be members of the DbContext derived type which itself is the generic argument of the convention.
Currently only the simplest result mapping where names of the columns returned from the database match the names of the names of the properties of the target type (except for mapping to scalar results) is supported. This is actually a limitation in the EF Code First where more complicated mappings would currently be ignored in most cases even though they are valid from the MSL perspective. There is a chance of having more complicated mappings enabled in EF 6.1.1 if appropriate changes are checked in by the time EF 6.1.1 ships. From here there should be just one step to enabling stored procedures returning multiple resultsets in Code First.
Now you probably are a bit tired of all this EF mumbo-jumbo and would like to see

The Code

To see the custom convention in action create a new (Console Application) project. Once the project has been created add the EntityFramework.CodeFirstStoreFunctions NuGet package. You can add it either from the Package Manager Console by executing

Install-Package EntityFramework.CodeFirstStoreFunctions -Pre 

command or using the UI – right click the References in the solution explorer and select “Manage NuGet Packages”, then when the dialog opens make sure that the “Include Prerelease” option in the dropdown at the top of the dialog is selected and use “storefunctions” in the search box to find the package. Finally click the “Install” button to install the package.

Code First Store Functions NuGet

Installing EntityFramework.CodeFirstStoreFunctions from UI

After the package has been installed copy and paste the code snippet from below to your project. This code demonstrates how to enable store functions in Code First.

public class Customer
    public int Id { get; set; }

    public string Name { get; set; }

    public string ZipCode { get; set; }

public class MyContext : DbContext
    static MyContext()
        Database.SetInitializer(new MyContextInitializer());

    public DbSet<Customer> Customers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
        modelBuilder.Conventions.Add(new FunctionsConvention<MyContext>("dbo"));

    [DbFunction("MyContext", "CustomersByZipCode")]
    public IQueryable<Customer> CustomersByZipCode(string zipCode)
        var zipCodeParameter = zipCode != null ?
            new ObjectParameter("ZipCode", zipCode) :
            new ObjectParameter("ZipCode", typeof(string));

        return ((IObjectContextAdapter)this).ObjectContext
                string.Format("[{0}].{1}", GetType().Name, 
                    "[CustomersByZipCode](@ZipCode)"), zipCodeParameter);

    public ObjectResult<Customer> GetCustomersByName(string name)
        var nameParameter = name != null ?
            new ObjectParameter("Name", name) :
            new ObjectParameter("Name", typeof(string));

        return ((IObjectContextAdapter)this).ObjectContext.
            ExecuteFunction<Customer>("GetCustomersByName", nameParameter);

public class MyContextInitializer : DropCreateDatabaseAlways<MyContext>
    public override void InitializeDatabase(MyContext context)

            "CREATE PROCEDURE [dbo].[GetCustomersByName] @Name nvarchar(max) AS " +
            "SELECT [Id], [Name], [ZipCode] " +
            "FROM [dbo].[Customers] " +
            "WHERE [Name] LIKE (@Name)");

            "CREATE FUNCTION [dbo].[CustomersByZipCode](@ZipCode nchar(5)) " +
            "RETURNS TABLE " +
            "RETURN " +
            "SELECT [Id], [Name], [ZipCode] " +
            "FROM [dbo].[Customers] " + 
            "WHERE [ZipCode] = @ZipCode");

    protected override void Seed(MyContext context)
        context.Customers.Add(new Customer {Name = "John", ZipCode = "98052"});
        context.Customers.Add(new Customer { Name = "Natasha", ZipCode = "98210" });
        context.Customers.Add(new Customer { Name = "Lin", ZipCode = "98052" });
        context.Customers.Add(new Customer { Name = "Josh", ZipCode = "90210" });
        context.Customers.Add(new Customer { Name = "Maria", ZipCode = "98074" });

class Program
    static void Main()
        using (var ctx = new MyContext())
            const string zipCode = "98052";
            var q = ctx.CustomersByZipCode(zipCode)
                .Where(c => c.Name.Length > 3);
            Console.WriteLine("TVF: CustomersByZipCode('{0}')", zipCode);
            foreach (var customer in q)
                Console.WriteLine("Id: {0}, Name: {1}, ZipCode: {2}", 
                    customer.Id, customer.Name, customer.ZipCode);

            const string name = "Jo%";
            Console.WriteLine("\nStored procedure: GetCustomersByName '{0}'", name);
            foreach (var customer in ctx.GetCustomersByName(name))
                Console.WriteLine("Id: {0}, Name: {1}, ZipCode: {2}", 
                    customer.Id, customer.Name, customer.ZipCode);   

In the code above I use a custom initializer to initialize the database and create a table-valued function and a stored procedure (in a real application you would probably use Code First Migrations for this). The initializer also populates the database with some data in the Seed method. The MyContext class is a class derived from the DbContext class and contains two methods that are mapped to store functions created in the initializer. The context class contains also the OnModelCreating method where we register the convention which will do all the hard work related to setting up our store functions. The Main method contains code that invokes store functions created when initializing the database. First, we use the TVF. Note, that we compose the query on the function which means that the whole query will be translated to SQL and executed on the database side. If you would like to see this you can uncomment the line which prints the SQL query in the above snippet and you will see the exact query that will be sent to the database:

    [Extent1].[Id] AS [Id],
    [Extent1].[Name] AS [Name],
    [Extent1].[ZipCode] AS [ZipCode]
    FROM [dbo].[CustomersByZipCode](@ZipCode) AS [Extent1]
    WHERE ( CAST(LEN([Extent1].[Name]) AS int)) > 3

(Back to the code) Next we execute the query and display results. Once we are done with the TVF we invoke the stored procedure. This is just an invocation because you cannot build queries on top of results returned by stored procedures. If you need any query-like (or other) logic it must be inside the stored procedure itself and otherwise you end up having a Linq query that is being run against materialized results. That’s pretty much the whole app. Just in case I am pasting the output the app produces below:

TVF: CustomersByZipCode('98052')
Id: 1, Name: John, ZipCode: 98052

Stored procedure: GetCustomersByName 'Jo%'
Id: 1, Name: John, ZipCode: 98052
Id: 4, Name: Josh, ZipCode: 90210
Press any key to continue . . .

Note that in both examples the return types are based on entity types. As I hinted above you can also use complex and scalar types for your results. Take a look at the End-to-End tests in the project itself – all scenarios are tested there.

That’s about what’s in alpha, so you may ask:

what’s next?

If you look at the code there are a few TODOs in the code. One of the most important is the support for nullable parameters. I am also thinking of removing the limitation where the method name in your DbContext derived class must ultimately match the name of the TVF in the database. If the workitem 2192 is resolved for the next version of EF I will be able to add support for non-default mapping. In addition I think it is very close from workitem 2192 to supporting stored procedures returning multiple resultsets. Not sure how useful it would be but it would be cool to see support for this feature which currently is kind of a dead feature because it is supported neither by CodeFirst nor by EF tooling.

Anything else?
The project is open source and is hosted on codeplex. You can get the sources from here. Try it and let me know what you think.


Using Pre-Generated Views Without Having To Pre-Generate Views (EF6)

To be able to work with different databases Entity Framework abstracts the store as a set of views which are later used to create queries and CUD (Create/Update/Delete) commands. EF generates views the first time it needs them (typically on the first query). For bigger or more complicated models view generation may take significant time and negatively impact the startup time of the application. This can be worked around by generating views at design time (e.g. using EF Power Tools or my T4 templates for generating views) and compiling them into you EF app.


  • There were significant improvements to view generation in EF6 (and more is coming), so make sure using pre-generated views visibly improve the startup time of your app – if they are not – don’t bother.
  • In EF6 (6.0.0 and 6.0.1) we saw several performance regressions (mostly in Code First) that affected the startup time of apps. They were not related to view generation (which in fact in most cases was faster than it was in EF5) so adding pre-generated views does not help. Many of these were fixed in 6.0.2. Always make sure you are running the latest bits and again check if view generation helps – if it does not – don’t bother.

So, for bigger models pre-generated views can help. But they are a bit bothersome. You need to remember about regenerating them each time your model changes. They add to the build time. They make your project more complicated. Not having to worry about views (especially that they are just an implementation detail that ideally would not be even exposed publicly if view generation did not impact the startup performance) makes the life of the developer much easier. Can we somehow combined these two worlds (and not in the way that the manual work done at design time impacts the startup time of the application :))? For instance, what if EF could check at runtime if up-to-date views are available and then use them if they are, or – if no usable views are available – it generates new views and stores them so that they are used the next time the application is run? This way the first time your app starts it will spend some time creating views (this time has to be spent somewhere anyways) but then (assuming the model has not changed) it will just use the views created when the app was run the first time which should result in faster startup time for subsequent runs. Sounds nice doesn’t it? And it actually is now possible. With the EFInteractiveViews NuGet package I published recently you can achieve all this with just a couple lines of code!

So, how does this work?

Assuming you have an existing EF6 application add the EFInteractiveViews NuGet packageto your project – you can right click on the References node in your project, select “Manage NuGet Packages” and add the NuGet package from the UI, or use the following command from the Package Manager Console:

Install-Package EFInteractiveViews

Once you add the package you need to decide where you want to store your views – you can use either a file or the database. If you want to store views in a file add the following code to your app:

using (var ctx = new MyContext())
            new FileViewCacheFactory(@"C:\MyViews.xml"));

Note that this code has to be executed before EF needs views (typically before you send the first query or the first call to the .SaveChanges() method) so make sure it is in the right place (for instance in a static constructor). The above line registers a view cache factory. Now if EF needs views it will first ask the registered view cache factory for views. The FileViewCacheFactory tries to load views from the file – if the file exists and the views match the model it will return views and EF will not need to generate views. If, however, the file does not exist or the views are outdated the FileViewCacheFactory will generate views, save them to the file and return them to EF.
Storing views in a file is kind of cool but since this is an EF app it has to have a database. Therefore storing views in the database would be even cooler. And this actually is possible – you just need to register a different view cache factory included in the package:

using (var ctx = new MyContext())
            new SqlServerViewCacheFactory(ctx.Database.Connection.ConnectionString));

Similarly to the FileViewCacheFactory you need to register the SqlServerViewCacheFactory before EF needs views. One more assumption the SqlServerViewCacheFactory makes is that the database exists (if this is not the case and you are using CodeFirst you can create one with ctx.Database.Initialize(force)). The SqlServerViewCacheFactory creates a table in your database to store views. By default the table will be called __ViewCache and will be in the dbo schema. You can change the defaults by passing the name of the table and/or schema in the SqlServerViewCacheFactory constructor.
As you probably guessed the SqlServerViewCacheFactory class is Sql Server specific. What if you are using a different back end? That’s not a big deal too. Create a new class derived from the DatabaseViewCacheFactory and implement three simple abstract methods – CreateConnection(), ViewTableExists() and CreateViewTable() and you are done. Since the EF Interactive Views project is open source you can take a look how I did it for SqlServer. (and yes, the DatabaseViewCacheFactory uses EF6 under the cover to get and update views in the database).

Words of precaution

When using interactive views make sure that you are not running different versions of an app (with different models) against the same database (CodeFirst typically does not allow this unless you are not using an initializer). If you do one version of an app will create views and then the other will not be able to use them so they will be overwritten which will make the views unusable for the version that ran originally and there will be no benefit in using interactive views at all.

That’s pretty much it. As I mentioned above the project is open source and you can find code on codeplex at Just in case here is the link to the NuGet package: Use, enjoy, comment and file bugs!

What changed in the EF Tooling in Visual Studio 2013 (and Visual Studio 2012 Out Of Band)

The recently shipped version of Visual Studio 2013 contains a new version of EF Tooling (a standalone version for Visual Studio 2012 is also available for download). The main goal of this release was to teach the EF designer how to talk to both EF5 and EF6. It was quite an undertaking given how EF6 differs from EF5 (binary incompatible, no correspondence between provider models and metadata workspace, EF6 runtime assemblies no longer in GAC just to name a few differences) and required changes to the existing functionality. Some of these changes may be confusing to people who used previous versions of EF tooling. The goal of this post is to take a look what has changed, why, and how it works now.
Before EF6 things were reasonably straightforward – from the EF Tooling standpoint there could be only one version of the EF runtime installed on the box – EF1, EF4 or EF5. In addition it was easy to determine the version of EF just by looking at the installed version of the .NET Framework – .NET Framework 3.5 meant EF1, .NET Framework 4 meant EF4 and .NET Framework 4.5 meant EF5. Note that the designer did not need to distinguish between EF4.x versions (treated as EF4) or EF5 for .NET Framework 4 (also treated as EF4) since they were built on top of the core EF runtime version residing in GAC. The installed (GAC’ed) version of the EF runtime automatically implied the latest supported version of Csdl, Ssdl, Msl and Edmx (‘schemas’ as we internally call them) since each version of the core EF runtime introduced a new version of schemas. But then happened EF6 – no longer in GAC, works on .NET Framework 4 and .NET Framework 4.5 (also meaning you could have v3 schemas on .NET Framework 4), binary incompatible with earlier versions of EF, some types moved to new/different namespaces, etc. The only way for tooling to be able to handle all of this was to break a number of assumptions made in the designer and, in some cases, change how the designer works. Below is a list of things that changed the most with a short explanation why they changed and what to expect:

  • For Model First the code is no longer generated when adding an empty model to the project. This is probably the most confusing change (funnily it was internally reported to me as a bug multiple times even before we shipped the new EF Tooling the first time in Visual Studio 2013 RC). The reason for this change is simple – since some types in EF6 were moved to different namespaces the code we used to generate for EF5 no longer works with EF6 (and vice versa). In some cases (e.g. you don’t have a reference to any EF runtime in your project) it is just impossible to tell whether the user is going it need EF5 or EF6 code. The most interesting part is that the code for we used to add when creating an empty model was is in reality not that useful before the database was created – yes, you could write code against the generated context/entities but you would not be really able to run it without the database. Therefore, we changed the workflow a bit and now the code generation templates are added when you create the database from model instead of when you add an empty model to your project because the wizard will make you select the version of EF you would like to use in your project, if there already isn’t one.
  • Code Generation Strategy disabled for EF6 models. Again this is partially related to changes to types and namespaces. Code generated for EF5 would not work with EF6. In addition the code we generate for ObjectContext based context and EntityObject based entities for EF5 (and earlier) applications is generated using System.Data.Entity.Design.dll. System.Data.Entity.Design.dll is part of the .NET Framework and does not fit into the EF6 shipping model. Therefore instead of updating System.Data.Entity.Design.dll we decided to support only T4 template based code generation for EF6. EF Tooling ships with T4 templates for generating DbContext based context and POCO entities. If, for some reason, you absolutely need ObjectContext based context the EF6 templates were posted on VS Gallery. For EF5 (or earlier) applications the Code Generation Strategy drop down is not blocked and you can choose between T4 and LegacyObjectContext (yes, we changed the option names as well because they were a bit ridiculous in VS2012 where ‘None’ basically meant T4 and ‘Default’ meant ObjectContext but the ‘None’ option was default).
  • Impossible to select the version of Entity Framework. To determine the applicable version of EF the designer looks for references to EntityFramework.dll and System.Data.Entity.dll in the project (note that EntityFramework.dll wins over System.Data.Entity.dll when determining the version). If it cannot find any, the user has to select the version in the wizard. Otherwise the latest version of EF found in the project is being used and the selection will not be possible (radio buttons will be disabled or the wizard page will not be shown at all).
  • Using third party providers. In the simple days of EF5 (and earlier) EF providers were registered globally and you could get one basically anytime and anywhere. Those days are long gone. In EF6 EF providers don’t have a global registration point. Rather, they are registered in the config file or using code based configuration. When you select a connection in the wizard the designer tries to find a reference to a corresponding provider in your project. If it cannot find one you won’t be able to use EF6 – instead you will be asked to close the wizard, install the provider and restart the wizard (note that this does not apply to the provider for Sql Server – EF Tooling contains EF6 provider for Sql Server which in the majority of cases make things easier for the user).
  • Retargeting. Depending on the referenced version of Entity Framework in the project changing the target .NET Framework version for the project may but may not change the edmx file. If the project references System.Data.Entity.dll and does not reference EF6 retargeting will result in upgrading/downgrading the version of the edmx file to match the latest supported version of the schema for the given .NET Framework and, as a result, EF runtime version. If the project contains a reference to EF6 toggling the target between .NET Framework 4 and .NET Framework 4.5 will not result in changing the edmx version since EF6 is supported on both versions and understands v3 schemas. Targeting .NET Framework 3.5 should always downgrade to v1 since EF1 is the only version available on .NET Framework 3.5. One caveat to retargeting is that you should always update your NuGet packages after retargeting. This is because EF (and potentially other packages) has a different assembly for .NET Framework 4 and for .NET Framework 4.5 (one of the reasons is that Async is not natively supported on .NET Frramework 4) and even though they are both shipped in the same NuGet package, NuGet does not replace project references after changing the target .NET Framework version. This leads either to missing functionality (e.g. Async not available on .NET Framework 4.5 (when using EF6 for .NET Framework 4 on .NET Framework 4.5)) or weird build errors saying you don’t have reference to EntityFramework.dll (only running MsBuild /v:diag will tell you that the reference you have was ignored since the referenced EntityFramework.dll was built for a later version of .NET Framework than the one the project is currently targeting (happens when using EF6 for .NET Framework 4.5 on .NET Framework 4)).
  • Using EF6 and EF5/EF4 in one project. Initially we did not want to support this scenario at all. However it is not only pretty easy to end up in such a situation but supporting this would also be helpful for people wanting to gradually move legacy, bigger projects from EF5 to EF6, so finally we decided to do what we can to support mixed EF versions in one project. The most important thing the designer has to do to handle this scenario correctly is to ensure that the right provider is being used for a given edmx file. Also, the version of the edmx file needs to be in sync with the referenced version of the EF runtime. Seems easy at first but there are some cases where things may behave a bit weird. A canonical example is when you have a project targeting .NET Framework 4 and you don’t have a reference to any Entity Framework runtime. When you create a new model it will create a v2 edmx since this was the latest supported schema version in .NET Framework 4. Now you create a database from your model and select EF6. Since EF6 supports v3 schemas the version of your edmx file will be changed to v3. Because the number of dimensions for versioning scenarios ended up being bigger than we originally expected and had a number of exceptions on top of that it was initially hard to tell what the outcome for each combination should be. To address this I created a set of rules which were much easier to understand and to follow when working on versioning scenarios. You can find these rules here.
  • In-the-box packages are not the latest available. EF Tooling contains EF6 NuGet packages that will be added to the project when adding a new model if needed. However, since EF Tooling ships with Visual Studio which has a different cadence that EF the included packages may not be the latest ones. In fact in case of EF6 we fixed a few (mostly performance related) bugs after Visual Studio 2013 was locked down. As a result version 6.0.1 of EF was shipped on the same day as Visual Studio 2013 but the version of EF that ships with Visual Studio 2013 is 6.0.0 and does not contain fixes included in 6.0.1. Moreover 6.0.2 is on its way and again – it will be a runtime only release. Updating EF package is as easy as running the following command from Package Manager Console (Tools → Library Package Manager → Package Manager Console)
    Update-Package EntityFramework

EF6 CodeFirst View Generation T4 Template for C# updated for EF6 RTM

The story around pre-generated views in pre-release versions of EF6 was far from glorious. First, things did not work in EF6 Beta1 due to this bug. Then the bug was fixed but due to other changes in this area pre-generated views were broken again in EF6 RC1 (mainly because of the combination of this and this). Because of the issues in the EF6 RC1 I decided not to post the version I had – it just did not work. Finally, it turned out that due to changes in the EF Tooling shipping with Visual Studio 2013 the template did not want to work on Visual Studio 2013 (or Visual Studio 2012 where the new tooling is available out-of-band). That’s a pretty interesting story on its own but for me it meant that I basically had to rewrite the template. Today EF6 has finally landed (btw. Visual Studio 2013 shipped today too) Since the bugs around pre-generated views were fixed I updated the EF6 Code First T4 template for generating views and posted the latest version on the Visual Studio Gallery. The template should work on Visual Studio 2010, Visual Studio 2012 and Visual Studio 2013 and for EF6 RTM and nightly builds. If you need steps to install and use the template take a look at this post.
A couple additional notes:
– an updated version of EF Power Tools which allows generating views (and more) directly from Visual Studio version was shipped recently
– view generation in EF6 has been greatly improved so maybe you don’t really need to use pre-generated views?

(Because you read this post you might be interested in this.)

My Late Reflections on T4

Friday the 13th – a perfect day for grumbling. And I mean it – it’s going to be counterproductive and is not going to help you with anything (at most you will be able to say “Me too!” or “I am not alone”). I am going to grumble about probably well known things and a few years too late. So if you are having a good day my advise would be to stop reading now. I typically don’t grumble but just move on but this time I already had the content so it made it easier. All this started with an email from a colleague from my old team looking for someone on the EF team who “owns” T4 templates. I answered that there is no such person since probably more than half people of the team had to deal with the templates so if he had any specific question he could send it to me and I would either answer or add to the thread someone who would be able to answer. It turned out that they had a tool that generates code – a kind of an .exe or something even worse (but not as bad as perl) and were looking at moving to T4 and he asked me what were my thoughts on this. The first thought was that moving to T4 was in general not a bad idea (and I still think it is given what they currently have). However when I started gathering “my thoughts” I concluded that every rose (even a dead one – pun intended) has its thorn.

  1. Out of the box a T4 template can spit just one file. This sucks a big time – you can end up having a file with hundreds of classes. There are some ways of working this around but they usually make your template cryptic and messy (as if it was already not the case) since all the logic has to live in the template itself
  2. Visual Studio does not have a built-in editor for T4. This makes it even harder to see what’s going on in the template (as if it was not hard enough). There are 3rd party tools/add-ons that provide syntax coloring and perhaps intellisense. I have not tried any them otherwise I could have one less thing to grumble about
  3. Developing T4 templates is messy. At first it feels a little bit like classic ASP. After a while you start adding some functions and soon the code looks pretty much like a classic ASP page which – when you scroll down – gradually turns into a kind of procedural code like C or Pascal. You could try using ttinclude but it does not help a lot – now ‘ASP’ is in one file and ‘Pascal’ in the other file
  4. If you have to ship templates generating code for both C# and VB.NET you most likely won’t be able to re-use most of the logic which means you have to replicate the code (as if shipping VB.NET version was not painful enough)
  5. T4 templates are basically not testable. To be able to write some kind of unit tests you would probably have to create a custom transformation host for testing. The problem is that even if you did that it does not solve the problem since T4 transformations can behave differently for different hosts so you would not be testing the thing the way it will eventually be used/executed anyways
  6. You supposedly can debug T4 templates. Realistically you can forget about it. For me it is like Santa – I know he exists but have never seen him. Maybe it works for very simple templates but once you start doing more complicated things it will just not work (never worked for me at least) and you will end up using “WriteLine” debugging – welcome to the nineteen-eighties
  7. If you screw something up, in the best case you will get an exception displayed in the error pane which – if you find the correct stack frame – sometimes can be even helpful. Otherwise you will just get a message saying “Error Generating Output” in your output file – and then you need to debug (see above)
  8. Some more advanced things may be impossible – I recently tried to spin a new AppDomain to run some code I could not run inside the transformation app domain (have you seen how my view gen templates break when you install new EF Designer? – I wanted to fix that by using a separate app domain) and had to give it up. Could not make it work since I did not have enough control over generating the class that included my transformation code, nor how the transformation is being run
  9. People are afraid of T4 and don’t realize that they can actually modify the template they added to the project and it will not break their Visual Studio. I think this is because of what they see when they open a T4 template first time (did I mention it looks messy and cryptic – especially if you don’t have syntax coloring?)
  10. It’s nice that you can ship T4 templates as vsix packages but Visual Studio is not really helpful in preparing those – at least I had to prepare the EF view gen templates mostly manually. I have been wanting to describe steps for shipping T4 templates as vsix files for a while but so far have not managed to

This is just grumbling – the T4 technology has been around for a while and my grumbling is not going to change anything there. I also don’t think there is anything better for text transformations that ships with Visual Studio so, as my mom would say, “if you can’t have what you like you have to like what you have”. Tomorrow will be a better day 🙂