EF CORE 2.1 HasConversion 在日期时间类型的所有属性上
Posted
技术标签:
【中文标题】EF CORE 2.1 HasConversion 在日期时间类型的所有属性上【英文标题】:EF CORE 2.1 HasConversion on all properties of type datetime 【发布时间】:2018-06-06 19:06:50 【问题描述】:我之前在读取实体时使用 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 Value Conversions 文档主题:
目前无法在一个地方指定给定类型的每个属性都必须使用相同的值转换器。未来版本将考虑此功能。
在此之前,您可以在 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);
【讨论】:
如果您在 DbContext optionsBuilder 上设置了 warningConfigurationBuilder.Throw(RelationalEventId.QueryClientEvaluationWarning),这将发出警告:“使用 ValueConverter 'ValueConverter只是觉得我可以投入两分钱
这里有一个问题: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;
【讨论】:
这是唯一在尝试使用列表和字典时也有效的方法。 @agritton 你能在这里分享你处理列表和字典的解决方案吗? @mreyeros 确定这里是代码。我正在使用它将我的列表和字典转换为 json 列。实际上它不适合评论,所以我将添加一个答案。 我认为这是正确的答案。谢谢,@康拉德!【参考方案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>());
【讨论】:
【参考方案4】:从 EF 核心 v6.0.0-preview6
开始,有一个更优雅的解决方案可以全局注册 ValueConverter。在这个例子中,我使用了一个自定义的 ISO8601 转换器,它在 UTC 中与 ISO8601 相互转换,最后总是附加 Z
:
public class DateTimeToIso8601StringConverter : ValueConverter<DateTime, string>
public DateTimeToIso8601StringConverter() : base(Serialize, Deserialize, null)
static Expression<Func<string, DateTime>> Deserialize = x => DateTime.Parse(x).ToUniversalTime();
static Expression<Func<DateTime, string>> Serialize = x => x.ToString("o", System.Globalization.CultureInfo.InvariantCulture);
在你的 DbContext
类中:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
configurationBuilder.Properties<DateTime>().HaveConversion<DateTimeToIso8601StringConverter>();
这避免了为每个模型属性单独指定转换器。
【讨论】:
以上是关于EF CORE 2.1 HasConversion 在日期时间类型的所有属性上的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Core 2.1 中引用 EF(Database First Approach)项目程序集
EF Core 2.1 中的 Eager loadingExplicit loading和LazyLoading (转自MSDN)