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

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

问题描述

我将 Entity Framework 5 与 Visual Studio 与 Entity Framework Power Tools Beta 2 结合使用,对中等大小的数据库(约 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(集合)和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.ttMapping.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.ttMapping.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.我用 '_' 将它们分开并使用数组中的最后一个字符串.我使用 RelationName 和 ToEndMember 属性来创建属性名称.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; }

现在你可能会问的代码.我已经向 T4 文件中的 CodeStringGenerator 类添加了 2 个函数.一种构建接收 NavigationProperty 的 propertyName.另一个为接收 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天全站免登陆