Utilisation d'un attribut personnalisé dans EF7 (core) OnModelCreating

c# ef-code-first entity-framework entity-framework-core npgsql

Question

J'ai un DefaultAttribute défini comme suit:

[AttributeUsage(AttributeTargets.Property)]
public class DefaultAttribute : Attribute
{
    /// <summary>
    /// Specifies this property has a default value upon creation.
    /// </summary>
    /// <param name="defaultValue">The default value of the property.</param>
    /// <param name="useAsLiteral">Set to true if the value is <em>not</em> quoted in the DDL.</param>
    public DefaultAttribute(object defaultValue, bool useAsLiteral = false)
    {
        DefaultValue = defaultValue;
        UseAsLiteral = useAsLiteral;
    }

    public object DefaultValue { get; private set; }

    /// <summary>
    /// True if the default value is not quoted in the DDL
    /// </summary>
    public bool UseAsLiteral { get; private set; }
}

J'ai décoré plusieurs de mes entités avec cet attribut, comme ceci:

public class MyEntity
{
    . . . (other properties) . . .
    [StringLength(200)]
    [Required]
    [Default("My Default Description!")]
    public string Description { get; set; }
}

Ensuite, dans ma méthode OnModelCreating dans le contexte de ma base de données, j'ai écrit le code suivant:

//examine custom annotations for shaping the schema in the database.
foreach (var entityType in builder.Model.GetEntityTypes())
    foreach (var property in entityType.GetProperties())
    {
        var annotations = property.GetAnnotations();

        // evaluate default values
        var defaultAnnotation = annotations.FirstOrDefault(x => x.Name == typeof(DefaultAttribute).FullName);
        if (defaultAnnotation != null)
        {
            var defaultValue = defaultAnnotation.Value as DefaultAttribute;
            if (defaultValue == null) continue;

            if (defaultValue.UseAsLiteral)
                property.Npgsql().DefaultValueSql = defaultValue.DefaultValue.ToString();
            else
                property.Npgsql().DefaultValue = defaultValue.DefaultValue;
        }
    }

Mon attente, lors de l'ajout d'une migration (et de la mise à jour ultérieure de la base de données), est que la valeur par défaut "My Default Description!" pour la colonne Description de MyEntity ... cependant, ce n'est pas le cas.

Je ne reçois aucune erreur, mais cela ne se passe pas comme je le soupçonne, et il est également difficile, inexplicablement, de se OnModelCreating dans OnModelCreating avec un point d'arrêt.

Est-ce que je le fais correctement? Est-ce que ça ne marche pas? Est-ce simplement pas pris en charge dans EF7? Ou n'est-ce pas pris en charge dans mon implémentation PostgreSQL? Toute idée serait appréciée.

MISE À JOUR Grâce à la réponse de @ IvanStoev, j'ai été en mesure de faire en sorte que cela fonctionne avec quelques modifications mineures (Reflection dans .NET Core un peu différent du traditionnel):

//examine custom annotations for shaping the schema in the database.
foreach (var entityType in builder.Model.GetEntityTypes())
    foreach (var property in entityType.GetProperties())
    {
        var memberInfo = property.PropertyInfo ?? (MemberInfo)property.FieldInfo;
        var defaultValue = memberInfo?.GetCustomAttribute<DefaultAttribute>();
        if (defaultValue == null) continue;
        if (defaultValue.UseAsLiteral)
            property.Npgsql().DefaultValueSql = defaultValue.DefaultValue.ToString();
        else
            property.Npgsql().DefaultValue = defaultValue.DefaultValue;
    }

Cela a fonctionné comme un champion.

Réponse acceptée

EF Core ne connaît rien de votre attribut personnalisé. Il est donc impossible de le découvrir et de l'exposer sous forme d'annotation (ce qui en général est une chose différente et pas nécessairement associée à un attribut).

Vous devez extraire l'attribut manuellement de PropertyInfo ou FieldInfo lorsqu'il est présent:

foreach (var entityType in builder.Model.GetEntityTypes())
    foreach (var property in entityType.GetProperties())
    {
        var memberInfo = property.PropertyInfo ?? (MemberInfo)property.FieldInfo;
        if (memberInfo == null) continue;
        var defaultValue = Attribute.GetCustomAttribute(memberInfo, typeof(DefaultAttribute)) as DefaultAttribute;
        if (defaultValue == null) continue;
        if (defaultValue.UseAsLiteral)
            property.Npgsql().DefaultValueSql = defaultValue.DefaultValue.ToString();
        else
            property.Npgsql().DefaultValue = defaultValue.DefaultValue;
    }


Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi