Adicionando atributos de propriedades personalizadas em código Entity Framework
-
20-08-2019 - |
Pergunta
Existe alguma maneira de adicionar atributos personalizados para propriedades no código gerado EF? A única coisa que eu posso ver como uma solução plausível seria a de chegar a um modelo personalizado T4. No entanto, devido à natureza do atributo que seria impossível determinar o parâmetro de atributo correto por EF propriedade.
Solução
Você pode fazer isso, especificando um tipo de metadados que os espelhos das propriedades e é usado simplesmente para atribuição.
[MetadataType(typeof(Dinner_Validation))]
public partial class Dinner
{}
public class Dinner_Validation
{
[Required]
public string Title { get; set; }
}
blogs Steve Smith sobre ele aqui .
Infelizmente a abordagem acima é frágil para refatoração. Outra opção é usar as novas entidades POCO. Estes geração de código em tempo de compilação evitar completamente, tanto quanto eu posso dizer. Eu não usei-los ainda assim não pode comentar sobre qualquer armadilhas ou compensações.
Outras dicas
Você pode adicionar este para o arquivo EDMX, com Designer também:
<Property Name="Nome" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" >
<Documentation>
<Summary>[MyCustomAttribute]</Summary>
</Documentation>
</Property>
E substituí-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)));
}
Com:
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)));
}
Você pode criar interface e atributo declare na interface.
partial class Person : IPerson {}
public interface IPerson
{
[Required]
string Name { get; set; }
}
Você pode adicionar este para o arquivo EDMX, com Designer também:
<Property Name="Nome" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" >
<Documentation>
<Summary>[MyCustomAttribute]</Summary>
</Documentation>
</Property>
E substituí-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)));
}
Com:
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)));
}
E para Entity Framework 6, substitua
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)));
}
com
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);
}
Advertências:
- Namespaces precisam ser resolvidas absolutamente.
- Assume atributos começam com '[' e terminam com ']' - nenhuma outra verificação de erros
- Se uma abertura e fechamento de cinta não for encontrado, a entidade resumo propriedade quadro é envolto em um comentário barra tripla XML.
- As tentativas para coincidir com informações padrão Visual Studio styling (realmente apenas travessões), que pode ou não ser o caso para o seu projeto. Isso inclui novas linhas.
saída da amostra:
/// <summary>
/// content type
/// </summary>
public System.Guid ContentType { get; set; }
[System.ComponentModel.DisplayName("Last Modified")]
public System.DateTime LastModified { get; set; }
Eu não acredito que você pode. O gerador declara todas as classes como parcial que lhe permite estendê-lo, mas não lhe permitirá marcar propriedades com atributos personalizados como ele vai simplesmente gerar sobre eles. A coisa que você pode fazer é escrever as suas próprias entidades.
Além de resposta de BurnsBA, Para aplicar esta a propriedades de navegação também, atualização NavigationProperty()
assim:
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);
}
Eu uso isso para adicionar [Newtonsoft.Json.JsonIgnore]
aos meus propriedades.
Nota: Você tem que adicioná-los para <...>Model.tt
e não <...>Model.Context.tt