【问题标题】:Adding custom property attributes in Entity Framework code在实体框架代码中添加自定义属性属性
【发布时间】:2010-11-06 05:57:29
【问题描述】:

有没有办法在 EF 生成的代码中向属性添加自定义属性?我认为唯一可行的解​​决方案是提供自定义 T4 模板。但是,由于属性的性质,不可能确定每个 EF 属性的正确属性参数。

【问题讨论】:

    标签: entity-framework custom-attributes


    【解决方案1】:

    除了 BurnsBA 的回复,要将其也应用于导航属性,请更新 NavigationProperty()

    public string NavigationProperty(NavigationProperty navProp)
    {
        var description = String.Empty;
        if(navProp.Documentation != null && string.IsNullOrWhiteSpace(navProp.Documentation.Summary) == false)
        {
            string summary = navProp.Documentation.Summary;
            if (!String.IsNullOrEmpty(summary) && summary.First() == '[' && summary.Last() == ']')
            {
                description = String.Format("\r\n\t{0}\r\n\t", summary);
            }
            else
            {
                description = String.Format("\r\n\t/// <summary>\r\n\t/// {0}\r\n\t/// </summary>\r\n\t", summary);
            }
        }
    
        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)),
            description);
    }
    

    我使用它来将[Newtonsoft.Json.JsonIgnore] 添加到我的属性中。

    注意:您必须将这些添加到 &lt;...&gt;Model.tt 而不是 &lt;...&gt;Model.Context.tt

    【讨论】:

      【解决方案2】:

      您可以将其添加到 EDMX 文件中,也可以使用 Designer:

      <Property Name="Nome" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" >
                  <Documentation>
                    <Summary>[MyCustomAttribute]</Summary>
                  </Documentation>
      </Property>
      

      并替换T4:

      void WriteProperty(CodeGenerationTools code, EdmProperty edmProperty)
      {
          WriteProperty(Accessibility.ForProperty(edmProperty),
                        code.Escape(edmProperty.TypeUsage),
                        code.Escape(edmProperty),
                        code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
                        code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
      }
      

      与:

      void WriteProperty(CodeGenerationTools code, EdmProperty edmProperty)
      {
          if(edmProperty.Documentation != null && string.IsNullOrWhiteSpace(edmProperty.Documentation.Summary) == false)
          {
          #>
          <#=edmProperty.Documentation.Summary#>
      <#+
          }
          WriteProperty(Accessibility.ForProperty(edmProperty),
                        code.Escape(edmProperty.TypeUsage),
                        code.Escape(edmProperty),
                        code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
                        code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
      }
      

      对于 Entity Framework 6,替换

      public string Property(EdmProperty edmProperty)
      {
          return string.Format(
              CultureInfo.InvariantCulture,
              "{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)));
      }
      

      public string Property(EdmProperty edmProperty)
      {
          var description = String.Empty;
          bool isAttribute = false;
      
          if(edmProperty.Documentation != null &&
              string.IsNullOrWhiteSpace(edmProperty.Documentation.Summary) == false)
          {
              string summary = edmProperty.Documentation.Summary;
              if (!String.IsNullOrEmpty(summary) && summary.First() == '[' && summary.Last() == ']')
              {
                  isAttribute = true;
              }
      
              if (isAttribute)
              {
                  description = String.Format("\r\n\t{0}\r\n\t", summary);
              }
              else
              {
                  description = String.Format("\r\n\t/// <summary>\r\n\t/// {0}\r\n\t/// </summary>\r\n\t", 
                      summary);
              }
      
          }
      
          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)),
              description);
      }
      

      警告:

      • 命名空间需要绝对解析。
      • 假设属性以 '[' 开头并以 ']' 结尾 -- 没有其他错误检查
      • 如果未找到左大括号和右大括号,实体框架属性摘要将包含在 XML 三斜杠注释中。
      • 尝试匹配默认的 Visual Studio 样式信息(实际上只是缩进),您的项目可能会也可能不会。这包括新行。

      样本输出:

      /// <summary>
      /// content type
      /// </summary>
      public System.Guid ContentType { get; set; }
      
      [System.ComponentModel.DisplayName("Last Modified")]
      public System.DateTime LastModified { get; set; }
      

      【讨论】:

        【解决方案3】:

        您可以将其添加到 EDMX 文件中,也可以使用 Designer:

        <Property Name="Nome" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" >
                    <Documentation>
                      <Summary>[MyCustomAttribute]</Summary>
                    </Documentation>
        </Property>
        

        并替换T4:

        void WriteProperty(CodeGenerationTools code, EdmProperty edmProperty)
        {
            WriteProperty(Accessibility.ForProperty(edmProperty),
                          code.Escape(edmProperty.TypeUsage),
                          code.Escape(edmProperty),
                          code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
                          code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
        }
        

        与:

        void WriteProperty(CodeGenerationTools code, EdmProperty edmProperty)
        {
            if(edmProperty.Documentation != null && string.IsNullOrWhiteSpace(edmProperty.Documentation.Summary) == false)
            {
            #>
            <#=edmProperty.Documentation.Summary#>
        <#+
            }
            WriteProperty(Accessibility.ForProperty(edmProperty),
                          code.Escape(edmProperty.TypeUsage),
                          code.Escape(edmProperty),
                          code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
                          code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
        }
        

        【讨论】:

        • 您好,我该如何更改 T4 模板?我创建了一个 Model1.tt 文件,它的所有文本都是黑色的,看起来像是另一种语法。
        • 更新,因为此答案可能已过时: 对于 EF 版本 6.2.0,您必须编辑方法 public string Property(EdmProperty edmProperty)public string NavigationProperty(NavigationProperty navProp)。答案中的 if 语句是相同的。
        【解决方案4】:

        您可以创建接口并在接口上声明属性。

        partial class Person : IPerson {}
        
        public interface IPerson
        {
            [Required]
            string Name { get; set; }
        }
        

        【讨论】:

        • 作为对未来读者的附注,这适用于 asp.net-mvc 的验证。
        • 如果你实现了 ValidationAttribute.IsValid 你可以反射到对象中并获取接口。从那里您可以获得该接口的成员并查找具有自定义属性的任何成员。我正在使用上述方法从日志记录中过滤掉任何具有 [Password] 属性的属性
        【解决方案5】:

        您可以通过指定反映属性并仅用于归因的元数据类型来做到这一点。

        [MetadataType(typeof(Dinner_Validation))] 
        public partial class Dinner 
        {} 
        
        public class Dinner_Validation 
        { 
            [Required] 
            public string Title { get; set; } 
        }
        

        Steve Smith 写了关于它的博客 here

        不幸的是,上述方法难以重构。另一种选择是使用新的 POCO 实体。据我所知,这些完全避免了编译时代码生成。我还没有使用它们,所以无法评论任何陷阱或权衡。

        【讨论】:

        • 当我突然意识到我的实体上的属性由于处理方式而实际上将不存在时,我刚刚爱上了 EF。 Grrrr。
        • 在反射时,assembly.GetType(typeof(Dinner).ToString().GetProperties()property.Attributes 为空,property.GetCustomAttributes(typeof(RequiredAttribute)) 返回一个长度为零的数组 - 应该反映 Dinner_Validation 还是其他错误?
        【解决方案6】:

        我不相信你可以。生成器将所有类声明为部分类,允许您对其进行扩展,但它不允许您使用自定义属性标记属性,因为它只会在它们之上生成。您可以做的一件事是编写自己的实体。

        【讨论】:

        • 可能是这种情况,但现在有一些选择。有关信息,请参阅我的答案。
        猜你喜欢
        • 2011-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多