EF CORE 2.1 HasConversion для всех свойств типа datetime
Ранее я использовал 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.
Ответы
Ответ 1
Выдержка из раздела документации по конверсии значений EF Core 2.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);
}
}
Ответ 2
Просто подумал, что смогу бросить свои два цента
Здесь открыта проблема для этого: https://github.com/aspnet/EntityFrameworkCore/issues/10784
Иван-решение будет работать для простых типов, таких как 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;
}
}
Ответ 3
Это не вписывается в раздел комментариев, поэтому я добавил ответ. Вот код, который я использую для преобразования списков и словарей.
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>());
}
}
}