web-dev-qa-db-fra.com

EF CORE 2.1 HasConversion sur toutes les propriétés de type datetime

J'ai précédemment utilisé DateTimeKindEntityMaterializerSource ( Git ) pour convertir tous les DateTime en UTC lors de la lecture d'entités car la valeur par défaut n'était pas spécifiée.

Avec EF core 2.1, DateTimeKindEntityMaterializerSource ne fonctionne plus, mais nous pouvons réellement le faire

         builder
        .Entity<ESDataQuotation>()
        .Property(e => e.CreatedDate)
        .HasConversion(v => v, v => DateTime.SpecifyKind(v, DateTimeKind.Utc));

Cependant, j'ai de nombreuses propriétés de DateTime et je voudrais s'il existe un moyen de faire la conversion pour toutes les propriétés de type DateTime.

13
Pilouk

Extrait d'EF Core 2.1 Conversions de valeur rubrique de documentation:

Il n'existe actuellement aucun moyen de spécifier en un seul endroit que chaque propriété d'un type donné doit utiliser le même convertisseur de valeur. Cette fonctionnalité sera envisagée pour une prochaine version.

D'ici là, vous pouvez utiliser la boucle typique à la fin de la substitution OnModelCreating où tous les types d'entités et les propriétés sont découverts:

var dateTimeConverter = new ValueConverter<DateTime, DateTime>(
    v => v, v => DateTime.SpecifyKind(v, DateTimeKind.Utc));

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
    foreach (var property in entityType.GetProperties())
    {
        if (property.ClrType == typeof(DateTime) || property.ClrType == typeof(DateTime?))
            property.SetValueConverter(dateTimeConverter);
    }
}
24
Ivan Stoev

Je pensais juste pouvoir mettre mes deux cents

Il y a un problème pour cela ouvert ici: https://github.com/aspnet/EntityFrameworkCore/issues/10784

La solution d'Ivan fonctionnera pour les types simples comme DateTime etc. mais elle plantera lors de l'utilisation de types définis par l'utilisateur lors de l'appel de entityType.GetProperties() ceci est mieux décrit dans le problème du lien ci-dessus. Pour le faire fonctionner avec des types définis par l'utilisateur, vous devrez utiliser entityType.ClrType.GetProperties().

Pour une solution universelle, vous pouvez utiliser cette méthode d'extension:

public static class ModelBuilderExtensions
{
    public static ModelBuilder UseValueConverterForType<T>(this ModelBuilder modelBuilder, ValueConverter converter)
    {
        return modelBuilder.UseValueConverterForType(typeof(T), converter);
    }

    public static ModelBuilder UseValueConverterForType(this ModelBuilder modelBuilder, Type type, ValueConverter converter)
    {
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            var properties = entityType.ClrType.GetProperties().Where(p => p.PropertyType == type);
            foreach (var property in properties)
            {
                modelBuilder.Entity(entityType.Name).Property(property.Name)
                    .HasConversion(converter);
            }
        }

        return modelBuilder;
    }
}
5
Konrad

Cela ne rentre pas dans la section des commentaires, j'ai donc ajouté une réponse. Voici le code que j'utilise pour convertir des listes et des dictionnaires.

foreach (var entity in builder.Model.GetEntityTypes())
        {
            foreach (var property in entity.ClrType.GetProperties())
            {
                if (property.PropertyType == typeof(List<string>))
                {
                    builder.Entity(entity.Name).Property(property.Name).HasConversion(new ValueConverter<List<string>, string>(v => v.ToJson(), v => v.FromJson<List<string>>())).HasColumnType("json");
                }
                else if (property.PropertyType == typeof(Dictionary<string, string>))
                {
                    builder.Entity(entity.Name).Property(property.Name).HasConversion(new ValueConverter<Dictionary<string, string>, string>(v => v.ToJson(), v => v.FromJson<Dictionary<string, string>>())).HasColumnType("json");
                }
                else if (property.PropertyType == typeof(List<List<string>>))
                {
                    builder.Entity(entity.Name).Property(property.Name).HasConversion(new ValueConverter<List<List<string>>, string>(v => v.ToJson(), v => v.FromJson<List<List<string>>>())).HasColumnType("json");
                }
                else if (property.PropertyType == typeof(bool))
                {
                    builder.Entity(entity.Name).Property(property.Name).HasConversion(new BoolToZeroOneConverter<short>());
                }
            }
        }
0
agritton