【发布时间】:2010-11-06 05:57:29
【问题描述】:
有没有办法在 EF 生成的代码中向属性添加自定义属性?我认为唯一可行的解决方案是提供自定义 T4 模板。但是,由于属性的性质,不可能确定每个 EF 属性的正确属性参数。
【问题讨论】:
标签: entity-framework custom-attributes
有没有办法在 EF 生成的代码中向属性添加自定义属性?我认为唯一可行的解决方案是提供自定义 T4 模板。但是,由于属性的性质,不可能确定每个 EF 属性的正确属性参数。
【问题讨论】:
标签: entity-framework custom-attributes
除了 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] 添加到我的属性中。
注意:您必须将这些添加到 <...>Model.tt 而不是 <...>Model.Context.tt
【讨论】:
您可以将其添加到 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);
}
样本输出:
/// <summary>
/// content type
/// </summary>
public System.Guid ContentType { get; set; }
[System.ComponentModel.DisplayName("Last Modified")]
public System.DateTime LastModified { get; set; }
【讨论】:
您可以将其添加到 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)));
}
【讨论】:
public string Property(EdmProperty edmProperty) 和 public string NavigationProperty(NavigationProperty navProp)。答案中的 if 语句是相同的。
您可以创建接口并在接口上声明属性。
partial class Person : IPerson {}
public interface IPerson
{
[Required]
string Name { get; set; }
}
【讨论】:
您可以通过指定反映属性并仅用于归因的元数据类型来做到这一点。
[MetadataType(typeof(Dinner_Validation))]
public partial class Dinner
{}
public class Dinner_Validation
{
[Required]
public string Title { get; set; }
}
Steve Smith 写了关于它的博客 here。
不幸的是,上述方法难以重构。另一种选择是使用新的 POCO 实体。据我所知,这些完全避免了编译时代码生成。我还没有使用它们,所以无法评论任何陷阱或权衡。
【讨论】:
assembly.GetType(typeof(Dinner).ToString().GetProperties()、property.Attributes 为空,property.GetCustomAttributes(typeof(RequiredAttribute)) 返回一个长度为零的数组 - 应该反映 Dinner_Validation 还是其他错误?
我不相信你可以。生成器将所有类声明为部分类,允许您对其进行扩展,但它不允许您使用自定义属性标记属性,因为它只会在它们之上生成。您可以做的一件事是编写自己的实体。
【讨论】: