Добавление атрибутов настраиваемых свойств в код Entity Framework

есть ли способ добавить пользовательские атрибуты в свойства в сгенерированном коде EF? Единственное, что я вижу, как правдоподобное решение будет придумать пользовательский шаблон T4. Однако из-за природы атрибута было бы невозможно определить правильный параметр атрибута для свойства EF.

6 ответов


вы можете сделать это, указав тип метаданных, который отражает свойства и используется просто для атрибуции.

[MetadataType(typeof(Dinner_Validation))] 
public partial class Dinner 
{} 

public class Dinner_Validation 
{ 
    [Required] 
    public string Title { get; set; } 
}

Стив Смит блоги об этом здесь.

к сожалению, приведенный выше подход хрупок для рефакторинга. Другой вариант-использовать новые объекты POCO. Насколько я могу судить, они полностью избегают генерации кода во время компиляции. Я не использовал их, поэтому не могу комментировать какие-либо подводные камни или недостатки.


вы можете добавить это в файл EDMX, с дизайнером также:

<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)));
}

вы можете создать интерфейс и объявить атрибут интерфейс.

partial class Person : IPerson {}

public interface IPerson
{
    [Required]
    string Name { get; set; }
}

вы можете добавить это в файл EDMX, с дизайнером также:

<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);
}

предупреждения:

  • пространства имен должны быть разрешены абсолютно.
  • предполагает, что атрибуты начинаются с ' ['и заканчиваются на'] ' -- нет другой проверки ошибок
  • если открывающая и закрывающая скобка не найдено, сводка свойств Entity framework завернута в комментарий тройной косой черты XML.
  • пытается сопоставить сведения о стиле visual studio по умолчанию (на самом деле просто отступы), которые могут быть или не быть для вашего проекта. Это включает в себя новые линии.

пример вывода:

/// <summary>
/// content type
/// </summary>
public System.Guid ContentType { get; set; }

[System.ComponentModel.DisplayName("Last Modified")]
public System.DateTime LastModified { get; set; }

Я не верю, что вы можете. Генератор объявляет все классы как частичные, позволяя вам расширить его, но он не позволит вам пометить свойства пользовательскими атрибутами, поскольку он будет просто генерировать над ними. Единственное, что вы можете сделать, это написать свои собственные сущности.


В дополнение к ответу 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