How do you change the code generated by L2S templates?

Mar 7, 2011 at 3:17 AM
Edited Mar 10, 2011 at 12:20 PM

Hello all

I would like to make slight adaptations to the code generated by LinqToSqlEntityClassTemplate (use List<> and direct references instead of EntitySet<> and EntityRef<>), but I'm having some issues understanding how to go about this.

This blog entry explains how template extension is intended to work. All you need to do is subclass an existing T4 template, override TransformText() and generate whatever code you need generated from there. You also need to tell the generator infrastructure how to access an instance of that template subclass. In my case:

 

// from file MyCustomLinqToSqlEntityClassTemplate.tt
public class MyCustomLinqToSqlEntityClassTemplate : LinqToSqlEntityClassTemplate
{
    ...

public override string TransformText()
  {
...
}
}

// from file MyDatabase.tt (subitem of MyDatabase.dbml) LinqToSqlGenerator generator = new LinqToSqlGenerator();
...
generator.EntityClassTemplate = new MyCustomLinqToSqlEntityClassTemplate();

generator.Run();

 

The issue I have with this is rooted in two facts:

  1. LinqToSqlGenerator.EntityClassTemplate is of the type LinqToSqlEntityClassTemplate. Hence, any template wanting to generate L2S entity classes MUST derive from LinqToSqlEntityClassTemplate
  2. Almost everything in LinqToSqlEntityClassTemplate is private, so MyCustomLinqToSqlEntityClassTemplate can't invoke any of its base class' members.

This works fine if my goal is simply to ADD to what LinqToSqlEntityClassTemplate generates. However, I wan't to CHANGE what LinqToSqlEntityClassTemplate generates. In my case MyCustomLinqToSqlEntityClassTemplate is a copy of LinqToSqlEntityClassTemplate in which I've deleted the few existing public members and made slight changes to a few of the methods. I think this smells for at least two reasons:

  • Lots of duplicate code (almost 100%) between classes related by inheritance.
  • I can't call base.TransformText() in my override, because MyCustomLinqToSqlEntityClassTemplate's implementation needs to be executed, not the base classes. As a result CSharpTemplate.TransformText() is never invoked (LinqToSqlEntityClassTemplate calls this in it's own overriden implementation of TransformText() ). This works right now, but Oleg will break my code if he ever decides to add anything important to CSharpTemplate.TransformText()'s implementation

IMHO this is very unfortunate, but wouldn't be hard to remedy by either one of the following:

  1. LinqToSqlGenerator.EntityClassTemplate remains as it is (of type LinqToSqlEntityClassTemplate) but LinqToSqlEntityClassTemplate is changed to allow for easy extensibility (methods are protected virtual, and rarely static)
  2. LinqToSqlGenerator.EntityClassTemplate is changed to reference an interface type (e.g. ILinqToSqlEntityClassTemplate) and LinqToSqlEntityClassTemplate remains as it is.

Have I not understood something? If my conclusions are correct, I would volunteer to submit a patch for the L2S templates in the T4Toolbox to accommodate for this scenario in whichever way Oleg/Community finds best (which is likely the interface based option, or something else I haven't thought of yet).

What do you think?