3

I'm investigating replacing or supplementing our home grown ORM system with the Entity Framework 4, and I'm noticing that the latter may end up causing a conflict between what we've defined as the naming conventions for our programming code and our databases. Being a Microsoft shop, we've largely decided to follow Microsoft's naming guidelines for our code, which say to use Pascal casing for members, namespaces, etc.; to avoid using underscores, and so on.

The default entity naming conventions in EF4, not surprisingly, work great with these standards. For example, an entity named SalesOrder will generate a class named SalesOrder and an entity set named SalesOrders. An EF4 Model-First design will, by default, generate a table of the same name as the entity set (in this example, the generated table name is SalesOrders). However, our database standards suggest to use all lowercase and underscores between words (e.g., sales_orders). So, using the Entity Framework "as is" will cause us to start deviating from them.

Is there anywhere in the Entity Framework where you can override it's behavior to use the entity set name as the SQL table name? I can't seem to find an obvious place to specify an alternate table name for the generated SQL script. If we go forward with using EF4, is the only plausible solution to have us reconsider our database naming conventions?

Update:

I'm trying Ladislav's solution below, but I can't seem to get the Generate Database from Model option in the Entity Framework model designer to recognize my custom utility. I have a file named MyOrg.EF.Utility.CS.ttinclude in the folder:

%VSINSTALLDIR%\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes

It essentially looks like this:

<#@ import namespace="Microsoft.CSharp"#>
<#@ import namespace="System.Text"#>


public class CustomUtilities
{
    public static string EntityNameToSqlName(string name)
    {
        string sqlName = "";    // The table name based on the input model name
        string pattern = "([A-Z]+[s])|([A-Z](?=[a-z]))|((?<=[a-z])[A-Z])";  //Pattern for the regex exp. below

        // Separate out each word with spaces:
        sqlName = System.Text.RegularExpressions.Regex.Replace(name, pattern, " $&");

        // Replace spaces with underscores and then make lowercase:
        sqlName = sqlName.Trim().Replace(" ", "_").ToLower();

        return sqlName;
    }

}

I've tried to reference this file in my custom .tt DDL generation file near the top as such:

<#@ include file="MyOrg.EF.Utility.CS.ttinclude"#>

However, if I try to reference the above function using code like this in the .tt file:

string tableName = CustomUtilities.EntityNameToSqlName(Id(entitySet.GetTableName()));

Visual Studio then complains that The name 'CustomUtilities' does not exist in the current context. Removing the class name from "CustomUtilities.EntityNameToSqlName" returns a similar error. Should I try a different way to insert a custom function into the DDL generation code?

Final solution:

I was able to finally get this working after I realized that I didn't wrap the C# code in my MyOrg.EF.Utility.CS.ttinclude file with this:

<#+
[my code]
#>

I also needed to add a public copy of the WriteColumns() method found in the file GenerateTSQL.Utility so that it would use my EntityNametoSqlName() method.

Unfortunately, my customized version of the original SSDLToSQL10.tt file is now a little messy, since I need to wrap CustomUtilities.EntityNameToSqlName() around quite a few items in there.

Derek
  • 952
  • 3
  • 13
  • 34

3 Answers3

5

The correct solution is to change your database naming convention.

Why should the tail wag the dog? In modern programming most of the action takes place in the highly scalable business/service layer, not the database. Programmers should use a naming convention that works for both - and it should cater to the needs of the application developer who is going to be working with these objects day in and day out. In some cases it should probably cater to the needs of the front end developer, in others the server side.

The whole purpose of a naming convention is to reduce complexity. Yet the accepted solution here is to implement all kinds of additional complexity. And every other ORM would have to come up with their own convoluted solution to this artificial problem.

GeorgeBarker
  • 991
  • 1
  • 11
  • 7
  • Good point. I agree that this is the simplest solution and is a good idea to implement where possible. But in the case I initialized proposed above, the database standard was rigidly defined long before the project I was working on, and changing our standards would then mean inconsistency with our historical products. At some point, though, you do need to consider drawing a metaphorical line in the sand and evaluating whether change would be for the best going forward. If programmers own the database, then the change you suggest is probably for the best. – Derek Oct 07 '13 at 15:53
  • I hear what you are saying - and I appreciate you raising the point in the first place. I'm hoping more people will find this discussion and weigh in. I'm guessing this is a source of a lot of waste. If I was a blogger I'd blog about it... – GeorgeBarker Oct 07 '13 at 19:12
  • 1
    The point of an ORM is to perform mapping as defined, not according to a single person's convention. Large teams with SQL developers would certainly not agree that the SQL team having its own conventions is "the tail wagging the dog". In fact, the ORM is more closely bound to the Store than an old-fashioned DAL, so if anything a requirement to adopt SQL names to meet OO conventions is inverted. Personally, I do not see any reason to avoid the same convention, but if we *require* them to be the same, we are creating an extremely long chain of name dependencies, and breaking SOC. – shannon Dec 06 '15 at 07:36
3

Sure there is. There is T4 template which converts your model to SQL DDL scripts. You can make a copy of this template and put your own logic for name generation into the new copy. After that you just need to set this template in your designer (DDL Generation Template property) and run Generate Database from Model ...

You will find default template in:

%VSINSTALLDIR%\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen\SSDLToSQL10.tt
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • This looks to be my best bet so far, though painfully complicated. I set up a clone of the **SSDLToSQL10.tt** file and did a slight tweak to it to turn all table names lowercase, and I was able to generate tables for my entity model using this new DDL generation template. I then went so far as to create a custom include file named **[My Organization's Name].EF.Utility.CS.ttinclude** in the directory: `%VSINSTALLDIR%\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes` However, I can't seem to be able to reference its main function in the above .tt file. – Derek Jul 14 '11 at 16:57
  • See my update at the top with what I've tried using a custom DDL generation template. – Derek Jul 14 '11 at 17:17
  • Ah ha! I got it working - I forgot to wrap the C# code in my .ttinclude file with `<# >` – Derek Jul 14 '11 at 20:14
0

You can do it . You need to implement a custom model builder to map your entities with relevant tables and relevant columns. You can override OnModelCreating function to build a custome model by adding this function to your context class.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
     modelBuilder.Entity<EntityName>().Map(c => c.ToTable("TableName"));//to map entity with table
     modelBuilder.Entity<EntityName>().Property(s => s.Property).HasColumnName("ColomnName");//to map properties with colomns
}
Jayantha Lal Sirisena
  • 21,216
  • 11
  • 71
  • 92
  • Where would you insert this code? I found something very similar on this blog: http://alensiljak.blogspot.com/2011/06/custom-table-mapping-with-entity.html but it's aimed at a Code-First approach, whereas I'm trying the Model-First approach since I'm more of a visual person. – Derek Jul 13 '11 at 16:31
  • Then you can do it in edmx designer.Right click on your entity in edmx diagram and choose table mapping. In that you can choose what table you are going to map and relevant columns for the properties of the entity. – Jayantha Lal Sirisena Jul 14 '11 at 02:23
  • You would think it would be that simple... However, when I try to change the table mapping like that, I'm only presented with a table name that matches the entity name, and I can't override it with something different (either an existing table already in the database or a new table name altogether). – Derek Jul 14 '11 at 16:52