在反向工程数据库时改进导航属性名称 [英] Improve navigation property names when reverse engineering a database

查看:131
本文介绍了在反向工程数据库时改进导航属性名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用具有实体框架Power Tools Beta 2的Visual Studio实体框架5来逆向工程中等大小的数据库(〜100个表)。

I'm using Entity Framework 5 with Visual Studio with Entity Framework Power Tools Beta 2 to reverse engineer moderately sized databases (~100 tables).

不幸的是, 导航属性没有有意义的名称。例如,如果有两个表:

Unfortunately, the navigation properties do not have meaningful names. For example, if there are two tables:

CREATE TABLE Contacts (
    ContactID INT IDENTITY (1, 1) NOT NULL,
    ...
    CONSTRAINT PK_Contacts PRIMARY KEY CLUSTERED (ContactID ASC)
}

CREATE TABLE Projects (
    ProjectID INT IDENTITY (1, 1) NOT NULL,
    TechnicalContactID INT NOT NULL,
    SalesContactID INT NOT NULL,
    ...
    CONSTRAINT PK_Projects PRIMARY KEY CLUSTERED (ProjectID ASC),
    CONSTRAINT FK_Projects_TechnicalContact FOREIGN KEY (TechnicalContactID)
        REFERENCES Contacts (ContactID),
    CONSTRAINT FK_Projects_SalesContact FOREIGN KEY (SalesContactID)
        REFERENCES Contacts (ContactID),
    ...
}

这将生成这样的类:

public class Contact
{
     public Contact()
     {
          this.Projects = new List<Project>();
          this.Projects1 = new List<Project>();
     }
     public int ContactID { get; set; }
     // ...
     public virtual ICollection<Project> Projects { get; set; }
     public virtual ICollection<Project> Projects1 { get; set; }
}

public class Project
{
     public Project()
     {

     }
     public int ProjectID { get; set; }
     public int TechnicalContactID { get; set; }
     public int SalesContactID { get; set; }
     // ...
     public virtual Contact Contact { get; set; }
     public virtual Contact Contact1 { get; set; }
}

我看到几种变体都会比这更好:

I see several variants which would all be better than this:


  • 使用外键的名称:例如,最后一个下划线之后的所有内容( FK_Projects_TechnicalContact - > TechnicalContact )。虽然这可能是最具控制力的解决方案,但这可能更难与现有模板集成。

  • 使用与外部对应的属性名称关键列:剥离后缀 ID TechnicalContactID - > TechnicalContact

  • 使用属性名称和现有解决方案的连接:示例 TechnicalContactIDProjects (collection )和 TechnicalContactIDContact

  • Use the name of the foreign key: For example, everything after the last underscore (FK_Projects_TechnicalContact --> TechnicalContact). Though this probably would be the solution with the most control, this may be more difficult to integrate with the existing templates.
  • Use the property name corresponding to the foreign key column: Strip off the suffix ID (TechnicalContactID --> TechnicalContact)
  • Use the concatenation of property name and the existing solution: Example TechnicalContactIDProjects (collection) and TechnicalContactIDContact

幸运的是,可以通过将模板包含在项目中来修改模板

必须对 Entity.tt Mapping.tt 。我觉得很难,因为缺乏智能感知和调试可能性来进行这些更改。

The modifications would have to be made to Entity.tt and Mapping.tt. I find it difficult due to the lack of intellisense and debug possibilities to make those changes.

连接属性名称(上面列出的第三个)可能是最简单的解决方案。

Concatenating property names (third in above list) is probably the easiest solution to implement.

如何更改 Entity.tt 和 Mapping.tt 以实现以下结果

How to change the creation of navigational properties in Entity.tt and Mapping.tt to achieve the following result:

public class Contact
{
     public Contact()
     {
          this.TechnicalContactIDProjects = new List<Project>();
          this.SalesContactIDProjects = new List<Project>();
     }
     public int ContactID { get; set; }
     // ...
     public virtual ICollection<Project> TechnicalContactIDProjects { get; set; }
     public virtual ICollection<Project> SalesContactIDProjects { get; set; }
}

public class Project
{
     public Project()
     {

     }
     public int ProjectID { get; set; }
     public int TechnicalContactID { get; set; }
     public int SalesContactID { get; set; }
     // ...
     public virtual Contact TechnicalContactIDContact { get; set; }
     public virtual Contact SalesContactIDContact { get; set; }
}


推荐答案

需要改变.tt文件里面。我选择使用您建议的第三个解决方案,但这需要格式化为FK_CollectionName_RelationName。我用'_'分割它们,并使用数组中的最后一个字符串。
我使用带有ToEndMember属性的RelationName创建一个属性名称。 FK_Projects_TechnicalContact将导致

There a few things you need to change inside the .tt file. I choose to use the third solution you suggested but this requires to be formatted like FK_CollectionName_RelationName. I split them up with '_' and use the last string in the array. I use the RelationName with the ToEndMember property to create a property name. FK_Projects_TechnicalContact will result in

//Plularized because of EF. 
public virtual Contacts TechnicalContactContacts { get; set; }

,您的项目将如此。

public virtual ICollection<Projects> SalesContactProjects { get;  set; }
public virtual ICollection<Projects> TechnicalContactProjects { get;  set; }

现在可以询问你的代码。 Ive在T4文件中的 CodeStringGenerator 类中添加了2个函数。一个构建propertyName接收NavigationProperty的。另一个生成接收NavigationProperty的属性的代码和属性的名称。

Now the code you may ask. Ive added 2 functions to the CodeStringGenerator class in the T4 file. One which builds the propertyName recieving a NavigationProperty. and the other one generating the code for the property recieving a NavigationProperty and the name for the property.

//CodeStringGenerator class
public string GetPropertyNameForNavigationProperty(NavigationProperty navigationProperty)
{
    var ForeignKeyName = navigationProperty.RelationshipType.Name.Split('_');
    var propertyName = ForeignKeyName[ForeignKeyName.Length-1] + navigationProperty.ToEndMember.Name;
    return propertyName;
}

public string NavigationProperty(NavigationProperty navigationProperty, string name)
{
    var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType());
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1} {2} {{ {3}get; {4}set; }}",
        AccessibilityAndVirtual(Accessibility.ForProperty(navigationProperty)),
        navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
        name,
        _code.SpaceAfter(Accessibility.ForGetter(navigationProperty)),
        _code.SpaceAfter(Accessibility.ForSetter(navigationProperty)));
}

如果将上述代码放在课堂中,您仍然需要更改2个部分。您需要找到构建器部分和导航属性部分正在构建的实体的位置。在构造函数部分(第60行)中,您需要通过调用方法 GetPropertyNameForNavigationProperty 替换现有代码,并将其传递到转义方法中。

If you place the above code in the class you still need to change 2 parts. You need to find the place where the constructor part and the navigation property part are being build up of the entity. In the constructor part (around line 60) you need to replace the existing code by calling the method GetPropertyNameForNavigationProperty and passing this into the escape method.

      var propName = codeStringGenerator.GetPropertyNameForNavigationProperty(navigationProperty);
#>
      this.<#=code.Escape(propName)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>();
<#

在NavigationProperties部分(100行左右),您还需要用以下代码替换代码。

And in the NavigationProperties part (around line 100) you also need to replace the code with the following.

    var propName = codeStringGenerator.GetPropertyNameForNavigationProperty(navigationProperty);
#>
    <#=codeStringGenerator.NavigationProperty(navigationProperty, propName)#>
<#

希望这有助于您,您可以随时调试 GetPropertyNameForNavigationProperty 函数,并使用该属性的命名来播放一下。

I hope this helps and you can always debug the GetPropertyNameForNavigationProperty function and play a little with the naming of the property.

这篇关于在反向工程数据库时改进导航属性名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆