web-dev-qa-db-ja.com

EF CORE 2.1日時型のすべてのプロパティのHasConversion

以前はデフォルトを指定しなかったため、エンティティの読み取り時にDateTimeKindEntityMaterializerSource( Git )を使用してすべてのDateTimeをUTCに変換しました。

EFコア2.1では、DateTimeKindEntityMaterializerSourceは機能しなくなりましたが、実際にこれを行うことができます

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

ただし、DateTimeの多くのプロパティがあり、DateTime型のすべてのプロパティの変換を行う方法があればいいと思います。

13
Pilouk

EF Core 2.1からの抜粋 値の変換 ドキュメントトピック:

現在、特定のタイプのすべてのプロパティが同じ値コンバーターを使用する必要があることを1か所で指定する方法はありません。この機能は、将来のリリースで検討されます。

それまでは、すべてのエンティティタイプとプロパティが検出されるOnModelCreatingオーバーライドの最後に典型的なループを使用できます。

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

ちょうど2セントを投入できると思った

ここで開かれた問題があります: https://github.com/aspnet/EntityFrameworkCore/issues/10784

IvanのソリューションはDateTimeなどのような単純な型に対して機能しますが、entityType.GetProperties()を呼び出すときにユーザー定義型を使用するとクラッシュします。これについては上記のリンクの問題で詳しく説明します。ユーザー定義型で動作させるには、entityType.ClrType.GetProperties()を使用する必要があります。

普遍的な回避策として、次の拡張メソッドを使用できます。

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

これはコメントセクションに収まらないため、回答を追加しました。リストと辞書を変換するために使用しているコードは次のとおりです。

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