Closed wdydxf closed 4 years ago
是否使用UTC时间还是应该按项目实际需要进行选择吧,我觉得框架武断引入会增加不少复杂度
DateTimeKind.Utc
类型DateTimeKind.Local
类型由 EFCore 负责将C#代码中的Local时间转换为Utc时间存储到数据库,将从数据库取出的Utc时间转换为Local时间到C#代码中使用
在实体的EntityConfiguration中,对时间类型的属性添加转换器,如下:
builder.Property(m => m.CreatedTime).HasConversion(local => local.ToUniversalTime(), utc => utc.ToLocalTime());
如此,每个实体的配置都要添加转换器,是件繁琐的事,可以通过DI注入解决
namespace OSharp.Entity
{
/// <summary>
/// 实体时间属性UTC转换器
/// </summary>
public interface IEntityDateTimeUtcConversion
{
/// <summary>
/// 转换指定的实体类型。
/// </summary>
/// <param name="entityType">实体类型</param>
void Convert(IMutableEntityType entityType);
}
}
namespace OSharp.Entity
{
/// <summary>
/// 实体时间属性UTC转换器
/// </summary>
/// <seealso cref="OSharp.Entity.IEntityDateTimeUtcConversion" />
public class EntityDateTimeUtcConversion : IEntityDateTimeUtcConversion
{
private readonly ValueConverter<DateTime, DateTime> _dateTimeConverter;
private readonly ValueConverter<DateTime?, DateTime?> _nullableDateTimeConverter;
/// <summary>
/// 初始化一个<see cref="EntityDateTimeUtcConversion"/>类型的新实例
/// </summary>
public EntityDateTimeUtcConversion()
{
_dateTimeConverter = new ValueConverter<DateTime, DateTime>(
local => local.ToUniversalTime(),
utc => utc.ToLocalTime());
_nullableDateTimeConverter = new ValueConverter<DateTime?, DateTime?>(
local => local.HasValue ? local.Value.ToUniversalTime() : local,
utc => utc.HasValue ? utc.Value.ToLocalTime() : utc);
}
/// <summary>
/// 转换指定的实体类型。
/// </summary>
/// <param name="entityType">实体类型</param>
public void Convert(IMutableEntityType entityType)
{
foreach (IMutableProperty property in entityType.GetProperties())
{
if (property.ClrType == typeof(DateTime))
{
property.SetValueConverter(_dateTimeConverter);
}
else if (property.ClrType == typeof(DateTime?))
{
property.SetValueConverter(_nullableDateTimeConverter);
}
}
}
}
}
在 EntityFrameworkCorePackBase
中
services.TryAddSingleton<IEntityDateTimeUtcConversion, EntityDateTimeUtcConversion>();
添加配置选项 DateTimeUtcFormatEnabled
,作为上下文是否启用UTC时间存储的开关
"SqlServer": {
"DbContextTypeName": "OSharp.Entity.DefaultDbContext,OSharp.EntityFrameworkCore",
"ConnectionString": "Data Source=osharp-mvc-dev.db",
"DatabaseType": "Sqlite",
"LazyLoadingProxiesEnabled": true,
"DateTimeUtcFormatEnabled": true,
"AuditEntityEnabled": true,
"AutoMigrationEnabled": true
}
List<IMutableEntityType> entityTypes = modelBuilder.Model.GetEntityTypes().ToList();
foreach (IMutableEntityType entityType in entityTypes)
{
//启用时间属性UTC格式
if (_osharpDbOptions.DateTimeUtcFormatEnabled)
{
IEntityDateTimeUtcConversion utcConversion = _serviceProvider.GetService<IEntityDateTimeUtcConversion>();
utcConversion.Convert(entityType);
}
// ...
}
IEntityBatchConfiguration
的实现: /// <summary>
/// 配置实体的时间属性的Utc时间转换,在数据库中保存Utc时间,在代码运行时使用当前时区的时间
/// </summary>
public class PropertyUtcDateTimeConfiguration : IEntityBatchConfiguration
{
private readonly IEntityManager _entityManager;
private readonly OsharpOptions _osharpOptions;
private readonly ValueConverter<DateTime, DateTime> _dateTimeConverter;
private readonly ValueConverter<DateTime?, DateTime?> _nullableDateTimeConverter;
/// <summary>
/// 初始化一个<see cref="PropertyUtcDateTimeConfiguration"/>类型的新实例
/// </summary>
public PropertyUtcDateTimeConfiguration(IServiceProvider provider)
{
_entityManager = provider.GetService<IEntityManager>();
_osharpOptions = provider.GetOSharpOptions();
_dateTimeConverter = new ValueConverter<DateTime, DateTime>(
local => local.ToUniversalTime(),
utc => utc.ToLocalTime());
_nullableDateTimeConverter = new ValueConverter<DateTime?, DateTime?>(
local => local.HasValue ? local.Value.ToUniversalTime() : local,
utc => utc.HasValue ? utc.Value.ToLocalTime() : utc);
}
/// <summary>
/// 配置指定的<see cref="IMutableEntityType"/>
/// </summary>
/// <param name="modelBuilder">模型构建器</param>
/// <param name="mutableEntityType">实体的<see cref="IMutableEntityType"/>类型</param>
public void Configure(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
{
foreach (IMutableProperty property in mutableEntityType.GetProperties())
{
if (property.ClrType == typeof(DateTime))
{
property.SetValueConverter(_dateTimeConverter);
}
else if (property.ClrType == typeof(DateTime?))
{
property.SetValueConverter(_nullableDateTimeConverter);
}
}
}
}
由于此功能涉及数据库中的数据统一性,使用配置来开关,有可能造成数据不一致的问题,是否启用此功能,应在代码层面固定,而不应能轻易在配置文件中更改,故而移除OSharpDbContextOptions
中的DateTimeUtcFormatEnabled
配置项
services.AddSingleton<IEntityBatchConfiguration, PropertyUtcDateTimeConfiguration>();
您的功能请求与现有问题有关吗?请描述
数据库表的时间字段, 能否修改为UTC时间, 框架如果能统一处理的话就更好了
描述您想要的解决方案
描述你考虑过的替代方案
现在方案也能用, 但如果框架能覆盖该功能的话, 适用更加广泛
附加上下文,比如截图
无