Customizing ‘Reverse Engineer Code First’ in the EF Power Tools

Posted on May 9, 2012. Filed under: Entity Framework, Visual Studio | Tags: , , , , |

Beta 2 of the Entity Framework Power Tools was recently released. By far the most popular feature out of these power tools is the ability to reverse engineer a Code First model from an existing database.

Admittedly ‘Code First’ wasn’t the best choice of names… Code First is really just a code-based alternate to the EF Designer, it supports creating a new database or mapping to an existing database. Using Code First against an existing database is often called ‘Code Second’ because… well… you have the database first and then write the code second.

I’ve included a download of the modified templates at the end of this post.

 

Reverse Engineer Code First

If you are already familiar with ‘Reverse Engineer Code First’ then skip ahead to the next section.

You’ll need the EF Power Tools installed from Visual Studio Gallery.

You start by right clicking on a project and selecting Entity Framework –> Reverse Engineer Code First:

ReverseEngineerCodeFirst

 

Then You’re prompted for details of the database you want to use:

SpecifyDatabase

 

A derived DbContext, a set of POCO classes and a set of mapping classes will be generated in a Models folder in your project:

GeneratedClasses

 

The Scenario

If you look in the mapping classes (those are the ones in the Mapping folder) you’ll see that ‘Reverse Engineer Code First’ uses the Fluent API for all it’s configuration.

FluentAPI

 

A common request is to use Data Annotations for configuration, rather than the Fluent API. You’ll also see that it generates table\column mapping code for all classes/properties, even though Code First would correctly work most of these out without configuration.

Let’s modify the code generation so that column and table mappings are done with Data Annotations and are only generated when required.

 

Adding the Reverse Engineer Templates

Right click on your project and select Entity Framework –> Customize Reverse Engineer Templates:

Customize

 

This will add a set of T4 templates to your project. The Power Tools will use these templates to generate the code for the various classes it adds to your project.

Templates

 

Note: You may see the following error after you add the templates. This is safe to ignore. It’s a result of Visual Studio trying to validate the templates… but they are never run from your project.

Compiling transformation: The type or namespace name ‘EfTextTemplateHost’ could not be found (are you missing a using directive or an assembly reference?)

 

Removing Fluent API Table/Column Mapping

The first step is to stop generating table and column mapping in the mapping classes. This is the easy part, in Beta 2 of the Power Tools just delete line 126 thru 152 (inclusive) from the Mapping.tt file.

Mapping

 

Adding Data Annotation Mapping

Now it’s time to edit Entity.tt to include the [Column] and [Table] attributes where required.

Let’s start by generating a [Column] attribute for any properties whose name doesn’t match the column that they map to.

This can happen when the column name contains characters that aren’t supported by C#. For example the column name may have a space, the reverse engineer process will generate a property that uses an underscore instead of a space. If we don’t supply any mapping then Code First will look for a column with an underscore instead of a space.

In Beta 2 you’ll find the property generation code around line 39 in Entity.tt, add the highlighted section from the code below.

    foreach (var property in efHost.EntityType.Properties)
    {

                var columnName = efHost.PropertyToColumnMappings[property].Name;
                if(code.Escape(property) != columnName)
                {
#>
        [Column("<#= columnName #>")]
<#
                }

#>
        <#= Accessibility.ForProperty(property) #> <#= code.Escape(property.TypeUsage) #> <#= code.Escape(property) #> { get; set; }
<#
    }

 

Next we need to generate a [Table] attribute when the pluralized name of the class doesn’t match the table it maps to.

This can happen if the table name is not pluralized in the database. For example, if you have a table named Category then the reverse engineer process will generate a class called Category. If you don’t supply any configuration then Code First will look for a table called Categories in the database. We also need to specify configuration if the table is not in the dbo schema.

In Beta 2 you’ll find the code that generates the class definition line around line 13 in Entity.tt, add the highlighted section from the code below.

namespace <#= code.EscapeNamespace(efHost.Namespace) #>
{
<#
        var tableName = (string)efHost.TableSet.MetadataProperties["Table"].Value ?? efHost.TableSet.Name;
        var conventionTableName = System.Data.Entity.Design.PluralizationServices.PluralizationService
                .CreateService(new CultureInfo("en"))
                .Pluralize(efHost.EntityType.Name);

        var schemaName = (string)efHost.TableSet.MetadataProperties["Schema"].Value;
        schemaName = string.IsNullOrWhiteSpace(schemaName)
                ? "dbo"
                : schemaName;

        if(schemaName != "dbo" || conventionTableName != tableName)
        {
#>
    [Table("<#= tableName #>", Schema="<#= schemaName #>")]
<#
        }

#>
   public class <#= efHost.EntityType.Name #>
    {
<#

 

The final step is to modify the template to generate a using for the namespace that the Data Annotations reside in. Add the highlighted code under the existing usings (around line 10 in the Beta 2 version of Entity.tt).

The namespace for the Table/Column annotations changed after EF4.3, so we check which version we are using and generate the correct namespace.

using System;
using System.Collections.Generic
;
<#
       if (efHost.EntityFrameworkVersion >= new Version(4, 4))
        {
#>
using System.ComponentModel.DataAnnotations.Schema;
<#
        }
        else
        {
#>
using System.ComponentModel.DataAnnotations;
<#
        }
#>

 

The Outcome

Now that we’ve made the edits you can re-run the reverse engineer process – make sure you save the changes to the tt files before you run it.

The table/column mapping code is now omitted from the configuration classes:

CleanFluentAPI

 

Where the mapping doesn’t line up with the Code First conventions we are now generating data annotations in the classes themselves:

DataAnnotationMapping

 

But if everything lines up then we don’t generate any mapping at all:

NoMapping

 

Conclusion

Here are the templates if you want to download them. It would be pretty simple to move specification of primary key etc. to use data annotations as well. You are welcome to edit and redistribute the templates as you see fit Smile

About these ads

Make a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

24 Responses to “Customizing ‘Reverse Engineer Code First’ in the EF Power Tools”

RSS Feed for RoMiller.com Comments RSS Feed

I’ve been contemplating using “Code First” in a new project I’m working on, but I enjoy developing the physical datamodel for the database the ‘old-fashioned’ way – so hearing about these reverse engineering tools helps to solidify my decision to use it.

Thanks for the post.

Rowan, any way you could start up a CodePlex or Github project for these templates, so we could more easily contribute improvements by forking the project?

Are there any ways to control the table names that get generated from code first reverse engineering? I’m would like to use this tool against an existing db, but there’s too much work involved in renaming tables after the tool generates code. Does the tool allow for some kind of mapping? Or, if not, how would I update the templates to use a custom mapping?

Thanks

Hi Rowan,

will be an RC version of the power tools soon or directly RTM?

cheers,
johannes

I have been unable to get this to work. I first followed the tutorial and when I ran the “Entity Framework > Reverse Engineer Code First” it seemed to ignore the templates and resulted in the same mappings that it created without the templates. Thinking I must have done something wrong I downloaded your templates, deleted all the files created from the previous attempt, cleared out the app.config file of any connection strings an ran it again … again it behaves as if it is ignoring the templates. Am I missing something?

Just tried this Rowan and it still generated fluent code and not Data Annotations. Seems like it didn’t read the changes I made? Any clues? Thanks,

Did you save the changes to the .TT files before re-running them?

I just want the reverse engineering to leave my table names alone, in all context. I don’t use spaces or underscores, but table names like Status become Statu. I have played with the plural vs singular and get varying results. I want my output to be, for example, DbSet Status and DbSet Contact (not DbSet Contacts )
This really can’t be that difficult.

I get the:
Compiling transformation: The type or namespace name ‘EfTextTemplateHost’ could not be found (are you missing a using directive or an assembly reference?)

How do you get rid of it? I don’t want to be left with a compile error?

Roam,

How to disable the pluralization on the T4 generation? This templates allways use pluralization on the relationships.

Do you have any solution to get rid of this?

Hi! I am starting a new app and would like to use the code first with an existing database approach. But it turns out to be a very big database, from which I just would like to pick a small subset of tables. Is it possible yo reverse engineer just a subset of tables from an existing database?

I am trying to generate code for some oracle tables, the first I see is (via ODAC tools for VS)

error 6003: Schema specified is not valid. Errors:
(1,607501) : error 2019: Member Mapping specified is not valid. The type ‘Edm.Decimal[Nullable=False,DefaultValue=,Precision=38,Scale=0]‘ of member ‘ITEM_DIVISION’ in type ‘dboModel.ITEM_DIVISIONS’ is not compatible with ‘OracleEFProvider.number[Nullable=False,DefaultValue=,Precision=3,Scale=0]‘ of member ‘DIVISION_ID’ in type ‘dbo.DIVISION_SHIPPING_LOCATIONS’.

see dbo, oracle don’t have any schema called dbo (its sqlserver stuff), also, it fails to generate code when the column size is number(38), Is there any way to fix these issues? I was able to generate code where tables don’t have number(38).

Also, I hate when the all caps classes (by default tables definition in oracle is all caps), Is there a way to convert the following:

public class DEPT
{
public DEPT()
{
this.EMPs = new List();
}

public short DEPTNO { get; set; }
public string DNAME { get; set; }
public string LOC { get; set; }
public virtual ICollection EMPs { get; set; }
}

to

public class Dept
{
public Dept()
{
this.Employees = new List();
}

public short Deptno { get; set; }
public string Dname { get; set; }
public string Loc { get; set; }
public virtual ICollection Employees { get; set; }
}

[...] Podemos modificar estas plantillas para que su comportamiento sea diferente, quitar los mapeos, evitar la pluralización en nuestras entidades, etc. Pincha el enlace para cómo,. [...]

Hi Rowan, I want to add another template to generate Dto classes. I copy and paste Entity template and changed name from Entity.tt to EntityDto.tt. Then ran reverse engineer toll. But it is not generating Dto classes. Could you please help me that can i include new template in EntityFramwork Power tools?

I ended up slightly modifying the files from Saber Soleymani since they resulted in some odd indentation for me. I made a repo in case others want to do pull requests, but hopefully if/when there’s a more official repo for customizing these templates, we can move them there. :)

Wondering, how would one add another tt template file, to generate another set of say, business object using the same approach as the Entity and have that executed? Or where would I find the doc’s that explain this item.

[…] by modifying the templates that are used to generate code. You can find an example of this in the Customizing ‘Reverse Engineer Code First’ in the EF Power Tools […]

[…] The code that gets generated by the reverse engineer process can be customized by modifying the templates that are used to generate code. You can find an example of this in the Customizing ‘Reverse Engineer Code First’ in the EF Power Tools post. […]

When i use a custom data type such as “public MultiSelectList lstQualifications { get; private set; }”,then causes error “Value cannot be null.
Parameter name: key”
How can i get rid of this problem.

[…] Luckily, it is possible to modify the templates by including them in the project. […]

Is it possible to create multiple DbContexts for multiple databases? The last time I checked, you could not do this with Code First.

Any way to have the models generated into the project’s root directory? I want my project to be called Models, so I don’t want a models folder inside that. Thanks!


Where's The Comment Form?

    About

    Rowan works as a Program Manager for the ADO.NET Entity Framework team at Microsoft. He speaks at technical conferences and blogs at romiller.com. Rowan lives in Seattle, Washington with his wife Athalie. Prior to moving to the US he resided in the small state of Tasmania in Australia. Outside of technology Rowan's passions include snowboarding, mountain biking, horse riding, rock climbing and pretty much anything else that involves being active. The primary focus of his life, however, is to follow Jesus.

    RSS

    Subscribe Via RSS

    • Subscribe with Bloglines
    • Add your feed to Newsburst from CNET News.com
    • Subscribe in Google Reader
    • Add to My Yahoo!
    • Subscribe in NewsGator Online
    • The latest comments to all posts in RSS

    Meta

Liked it here?
Why not try sites on the blogroll...

Follow

Get every new post delivered to your Inbox.

Join 163 other followers

%d bloggers like this: