Utilizzo di un attributo personalizzato in EF7 (core) OnModelCreating

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

Domanda

Ho definito DefaultAttribute modo:

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

Ho decorato diverse delle mie entità con questo attributo, in questo modo:

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

Quindi, nel mio metodo OnModelCreating nel mio contesto di database, ho scritto il seguente codice:

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

La mia aspettativa, quando aggiungo una migrazione, (e il successivo aggiornamento del database) è che ci sarebbe un valore predefinito di "La mia descrizione predefinita!" per la colonna Description di MyEntity ... tuttavia, questo non è il caso.

Non ricevo errori, ma non lo faccio come sospetto, e anche entrare in OnModelCreating con un punto di interruzione è inspiegabilmente difficile da fare.

Sto facendo questo correttamente? Non funziona? Non è supportato solo in EF7? Oppure non è supportato nella mia implementazione di PostgreSQL? Qualsiasi intuizione sarebbe apprezzata.

AGGIORNAMENTO Usando la risposta di @ IvanStoev, sono riuscito a farlo funzionare con alcune modifchezioni minori (Reflection in .NET Core un po 'diverso dal tradizionale):

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

Questo ha funzionato come un campione.

Risposta accettata

EF Core non sa nulla del tuo attributo personalizzato, quindi non c'è modo di essere scoperto ed esposto come annotazione (che in generale è una cosa diversa e non necessariamente associata all'attributo).

Devi estrarre manualmente l'attributo da PropertyInfo o FieldInfo quando presenti:

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

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché