逆向工程数据库时改进导航属性名称

mar*_*pet 53 t4 entity-framework ef-code-first entity-framework-5 ef-power-tools

我正在使用带有Entity Framework Power Tools Beta 2的Visual Studio的Entity Framework 5来反向设计中等大小的数据库(~100个表).

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

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),
    ...
}
Run Code Online (Sandbox Code Playgroud)

这将生成如下类:

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; }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 使用外键名称:例如,最后一个下划线(FK_Projects_TechnicalContact- > TechnicalContact)之后的所有内容.虽然这可能是具有最多控制权的解决方案,但这可能更难以与现有模板集成.
  • 使用与外键列对应的属性名称:去掉后缀ID(TechnicalContactID- > TechnicalContact)
  • 使用属性名称和现有解决方案串联:示例TechnicalContactIDProjects(集合)和TechnicalContactIDContact

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

这些修改必须要进行Entity.ttMapping.tt.由于缺乏智能感知和调试可能性来进行这些更改,我觉得很难.


连接属性名称(上面列表中的第三个)可能是最容易实现的解决方案.

如何更改导航属性的创建Entity.ttMapping.tt实现以下结果:

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; }
}
Run Code Online (Sandbox Code Playgroud)

Rik*_*erg 48

您需要在.tt文件中更改一些内容.我选择使用您建议的第三种解决方案,但这需要格式化为FK_CollectionName_RelationName.我用'_'将它们拆分并使用数组中的最后一个字符串.我使用RelationName和ToEndMember属性来创建属性名称.FK_Projects_TechnicalContact将导致

//Plularized because of EF. 
public virtual Contacts TechnicalContactContacts { get; set; }
Run Code Online (Sandbox Code Playgroud)

你的项目就是这样的.

public virtual ICollection<Projects> SalesContactProjects { get;  set; }
public virtual ICollection<Projects> TechnicalContactProjects { get;  set; }
Run Code Online (Sandbox Code Playgroud)

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

//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)));
}
Run Code Online (Sandbox Code Playgroud)

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

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

在NavigationProperties部分(第100行)中,您还需要使用以下代码替换代码.

    var propName = codeStringGenerator.GetPropertyNameForNavigationProperty(navigationProperty);
#>
    <#=codeStringGenerator.NavigationProperty(navigationProperty, propName)#>
<#
Run Code Online (Sandbox Code Playgroud)

我希望这会GetPropertyNameForNavigationProperty有所帮助,您可以随时调试该功能并使用该属性的命名进行一些操作.

  • 我收到一条错误消息,说明所需的属性不存在.它仍然*想要*可怕的导航属性.我需要实际更改导航属性,而不是仅仅更改模型的编写方式 (4认同)
  • 我将修改后的模板放在github(http://git.io/I2iNGw)上,并在foreignkeyname分支中调整您的输入.我最终可能会使用另一个版本(propertyname分支),因为各种数据库中外键的命名并不像我预期的那样一致.代码远非优雅,可以使用一些t4-ninja-love来减少重复,但我只想在发布新版本的Power Tools时保持简单更新. (2认同)

3-1*_*264 7

基于BikeMrown的答案,我们可以使用RelationshipNameMSSQL中设置的属性将Intellisense添加到属性中:

MSSQL关系

在VS Project中编辑model.tt,然后更改:

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
<#
            }
#>
    <#=codeStringGenerator.NavigationProperty(navigationProperty)#>
<#
        }
    }
Run Code Online (Sandbox Code Playgroud)

对此:

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
<#
            }
#>
    /// <summary>
    /// RelationshipName: <#=code.Escape(navigationProperty.RelationshipType.Name)#>
    /// </summary>
    <#=codeStringGenerator.NavigationProperty(navigationProperty)#>
<#
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在,当您开始键入属性名称时,您会收到如下工具提示: 智能感知工具提示

值得注意的是,如果更改数据库模型,属性可能会发现自己指向不同的数据库字段,因为EF会根据各自的数据库字段名称的字母优先级生成导航属性名称!