【问题标题】:EntityFramework t4 template - XML documentationEntityFramework t4 模板 - XML 文档
【发布时间】:2013-12-11 15:01:35
【问题描述】:

我的 EDMX 文件存在以下问题。

在其中我为属性和实体编写了一些文档,但是我的 EF 5 的 t4 模板不会生成这些值。

我想要的结果应该是

public class Person
{
    /// <summary>
    /// Hello World Summary!!
    /// </summary>
    /// <remarks>
    /// Hello World Remarks!!
    /// </remarks>
    public string Name { get; set; }
}

但我只得到

public class Person
{
    public string Name { get; set; }
}

如果不是为了这个,为什么我还能在 edmx 文件中设置文档属性。

【问题讨论】:

    标签: c# entity-framework entity-framework-5 t4 xml-comments


    【解决方案1】:

    似乎实体框架不会通过代码文档为您生成对象,而且我在 nuget 上看不到解决方案,这很遗憾。

    您可以修改 T4 模板来为您执行此操作,而无需太多麻烦。为了让您开始,如果您打开实体的 T4 模板,并找到如下所示的行(对我来说大约是第 74 行):

        <#=codeStringGenerator.Property(edmProperty)#>
    

    然后改成这样:

    <# if (edmProperty != null && edmProperty.Documentation != null) {#>
    /// <summary>
    /// <#= edmProperty.Documentation.Summary #>
    /// </summary>
    /// <remarks>
    /// <#= edmProperty.Documentation.LongDescription #>
    /// </remarks>
    <# } #>
        <#=codeStringGenerator.Property(edmProperty)#>
    

    这将为您的属性生成文档。

    如果你走到像这样的行(对我来说大约是第 28 行):

    <#=codeStringGenerator.EntityClassOpening(entity)#>
    

    然后改成这样:

    <# if (entity != null && entity.Documentation != null) {#>
    /// <summary>
    /// <#= entity.Documentation.Summary #>
    /// </summary>
    /// <remarks>
    /// <#= entity.Documentation.LongDescription #>
    /// </remarks>
    <# } #>
    <#=codeStringGenerator.EntityClassOpening(entity)#>
    

    这应该会给你你的课程文档。

    可能还有一些其他地方需要更新(例如复杂和导航属性),但它应该可以帮助您完成大部分工作。

    马特

    【讨论】:

    • 谢谢,很有帮助!关于处理文档中换行符的最佳方法有什么建议吗?使用上述方法,注释 (///) 不会为 Summary\LongDescription 中的每个换行符重复
    • 实际上是在做类似的事情: edmProperty.Documentation.Summary.Replace("\n", "\r\n\t/// ") 就可以了,它还可以防止烦人视觉工作室关于行尾的警告不一致。
    【解决方案2】:

    这是我的看法。

    在你的 .tt 文件中生成的CodeStringGenerator 类中,我添加了这个方法:

    private string Comments(EdmMember member)
    {
        string comments = member.Documentation != null
            ? (string.IsNullOrEmpty(member.Documentation.Summary)
                ? ""
                : @"
    /// <summary>
    /// " + member.Documentation.Summary.Replace("\n", Environment.NewLine + "    /// ") + @" 
    /// </summary>
    ")
                +
                (string.IsNullOrEmpty(member.Documentation.LongDescription)
                ? ""
                : @"/// <remarks>
    /// " + member.Documentation.LongDescription.Replace("\n", Environment.NewLine + "    /// ") + @"
    /// </remarks>
    ")
            : "";
        return comments;
    }
    

    我承认这个方法有两个问题:a) 它假设了一定程度的缩进,虽然这是一个属性的预期缩进级别,b) 如果没有摘要,则在注释前添加一个额外的行。但这不太可能发生。

    然后,我从生成简单和导航属性的方法中调用这个方法:

    public string Property(EdmProperty edmProperty)
    {
        string comments = Comments(edmProperty);
        return string.Format(
            CultureInfo.InvariantCulture,
            @"{5}{0} {1} {2} {{ {3}get; {4}set; }}",
            Accessibility.ForProperty(edmProperty),
            _typeMapper.GetTypeName(edmProperty.TypeUsage),
            _code.Escape(edmProperty),
            _code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
            _code.SpaceAfter(Accessibility.ForSetter(edmProperty)),
            comments);
    }
    
    public string NavigationProperty(NavigationProperty navProp)
    {
        string comments = Comments(navProp);
        var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType());
        return string.Format(
            CultureInfo.InvariantCulture,
            "{5}{0} {1} {2} {{ {3}get; {4}set; }}",
            AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)),
            navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
            _code.Escape(navProp),
            _code.SpaceAfter(Accessibility.ForGetter(navProp)),
            _code.SpaceAfter(Accessibility.ForSetter(navProp)),
            comments);
    }
    

    【讨论】:

      【解决方案3】:

      我想在 Matt Mhetton 的回答中添加更多详细信息,因为由于我当前的项目配置(CA 和 Style cop),所有内容都必须记录在案。

      一方面,您必须在设计器中为您想要记录的所有内容(类、简单属性、复杂属性和导航属性)添加文档属性

      另一方面,您必须打开您创建的 WhatModel.tt 并对其进行编辑以包含文档,我将逐步解释:

      1.- 对于类文档,请查找:

      <#=codeStringGenerator.UsingDirectives(inHeader: false)#>
      <#=codeStringGenerator.EntityClassOpening(entity)#>
      

      (在我的情况下为第 26 行)并将您的 cmets 放在这两行之间,如下所示:

      <#=codeStringGenerator.UsingDirectives(inHeader: false)#>
      <# if (entity != null && entity.Documentation != null) {#>
      /// <summary>
      /// <#= entity.Documentation.Summary #>
      /// </summary>
      <# } #>
      <#=codeStringGenerator.EntityClassOpening(entity)#>
      

      2.- 对于 constructor 文档 查找 public &lt;#=code.Escape(entity)#&gt;() thaqt 是生成构造函数的内容,因此请将您的文档放在该行之前,如下所示:

      <# if (entity != null && entity.Documentation != null) {#>
          /// <summary>
          /// <#= entity.Documentation.Summary #>
          /// </summary>
      <# } #>
          public <#=code.Escape(entity)#>()
          {
      

      3.- 要记录每个属性,请查找foreach (var edmProperty in simpleProperties),此外观将生成属性代码,因此,它应如下所示:

      foreach (var edmProperty in simpleProperties)
              {
      #>
      <# if (edmProperty != null && edmProperty.Documentation != null) {#>    
          /// <summary>
          /// <#= edmProperty.Documentation.Summary #>
          /// </summary>
      <# } #>
          <#=codeStringGenerator.Property(edmProperty)#>
      <#
      
              }
      

      (注意:这适用于简单属性,但对于复杂属性将采用相同的方式...)

      4.- 对于 导航属性 完全相同,查找 foreach (var navigationProperty in navigationProperties) 并添加您的文档,如下所示:

      foreach (var navigationProperty in navigationProperties)
              {
      #>
      <# if (navigationProperty != null && navigationProperty.Documentation != null) {#>
          /// <summary>
          /// <#= navigationProperty.Documentation.Summary #>
          /// </summary>
      <# } #>
          <#=codeStringGenerator.NavigationProperty(navigationProperty)#>
      <#
      
              }
      

      4.- 最后但同样重要的是,如果您还需要 上下文类中的文档,您可以使用它(查找 &lt;# if (code.Escape(container) != null) {#&gt;):

      <# if (code.Escape(container) != null) {#>
      /// <summary>
      /// Represents <#= code.Escape(container) #>
      /// </summary>
      <# } #>
      <#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
      {
      
      <# if (code.Escape(container) != null) {#>
          /// <summary>
          /// Initializes a new instance of the <see cref="<#= code.Escape(container) #>"/> class.
          /// </summary>
      <# } #>
          public <#=code.Escape(container)#>()
          : base("name=<#=container.Name#>")
          {
      <#
      if (!loader.IsLazyLoadingEnabled(container))
      {
      #>
              this.Configuration.LazyLoadingEnabled = false;
      <#
      }
      #>
          }
      
          /// <summary>
          /// On Model Creating
          /// </summary>
          protected override void OnModelCreating(DbModelBuilder modelBuilder)
          {
              throw new UnintentionalCodeFirstException();
          }
      
      <#
          foreach (var entitySet in container.BaseEntitySets.OfType<EntitySet>())
          {
      #>
      
         <# if (code.Escape(entitySet) != null) {#>
          /// <summary>
          /// Gets or sets the <#=code.Escape(entitySet)#>
          /// </summary>
          <# } #>
      

      我希望它能像马特惠顿的回答一样帮助我(谢谢马特)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-07
        • 2011-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多