【问题标题】:EntityFramework Core format DateTime in sqlite databasesqlite数据库中的EntityFramework Core格式DateTime
【发布时间】:2018-03-13 16:45:10
【问题描述】:

我正在使用带有 SQLite 的 EF Core 2.0,并且我想减小我的数据库的大小,而不会丢失我的表列中人类可读的日期时间值。目前,数据上下文将完整的 DateTime CLR 对象存储为像“2018-03-10 16:18:17.1013863”这样的字符串,但在我的情况下,“2018-03-10 16:18:17”就足够了。我该怎么办?

【问题讨论】:

  • @mason SQLite 没有日期时间类型——你必须使用文本
  • 我已经在使用 TEXT。每个条目存储毫秒。我不想存储这些数据。

标签: c# database datetime entity-framework-core ef-core-2.0


【解决方案1】:

如果小数秒为零,则不会存储它们。您可以安全地从现有数据中删除它们。更新您的应用程序以不指定它们。您可以急切地执行此操作(当您在实体上设置 DateTime 值时)或在 SaveChanges 期间懒惰地执行此操作。

public override int SaveChanges()
{
    var dateTimeProperties =
        from e in ChangeTracker.Entries()
        where e.State == EntityState.Added
                || e.State == EntityState.Modified
        from p in e.Properties
        where p.CurrentValue is DateTime
        select p;
    foreach (var property in dateTimeProperties)
    {
        // Strip millisecond
        var value = (DateTime)property.CurrentValue;
        property.CurrentValue = new DateTime(
            value.Year,
            value.Month,
            value.Day,
            value.Hour,
            value.Minute,
            value.Second);
    }

    return base.SaveChanges();
}

【讨论】:

  • 难道没有办法覆盖 CLR 类型映射到数据库的方式吗?就像不是从 CLR 调用 DateTime.ToString(format:"...") 到数据库映射,而是只调用 DateTime.ToString("G") 或类似的?如果 EF Core 2.0 不可能,也许 2.1(约定)?
  • 2.1 版将允许value conversions 用于此目的。
【解决方案2】:

添加 bricelam 回复。用于修剪毫秒的更好(更短和更快)的代码是:

property.CurrentValue = value.AddTicks(-value.Ticks % TimeSpan.TicksPerSecond)

【讨论】:

    【解决方案3】:

    如果您真的想剃掉更多尺寸,可以为要缩小尺寸的每一列添加自定义转换,如下所示:

     protected override void OnModelCreating(ModelBuilder constructor) =>
     constructor.Entity<YourEntity>().Property(c => c.DatePropertyOfYourEntity)
                        .HasConversion(f => f.ATextoYYMMDD(), s => s.AFechaYYMMDD());
    

    我使用了以下扩展方法在日期和字符串格式YYMMDD之间进行非常快速的转换:

        public static string ATextoYYMMDD(this DateTime fechaHora) {
    
            var chars = new char[6];
            var valor = fechaHora.Year % 100;
            chars[0] = (char)(valor / 10 + '0');
            chars[1] = (char)(valor % 10 + '0');
            valor = fechaHora.Month;
            chars[2] = (char)(valor / 10 + '0');
            chars[3] = (char)(valor % 10 + '0');
            valor = fechaHora.Day;
            chars[4] = (char)(valor / 10 + '0');
            chars[5] = (char)(valor % 10 + '0');
            return new string(chars);
    
        } 
    
        public static DateTime AFechaYYMMDD(this string s)
            => new DateTime((s[0] - '0') * 10 + s[1] - '0' + 2000, 
            (s[2] - '0') * 10 + s[3] - '0', (s[4] - '0') * 10 + s[5] - '0');
    

    如果你想将它应用到多个实现接口的实体上,你可以这样做:

                var convertidor = new ValueConverter<DateTime, string>
                    (f => f.ATextoYYMMDD(), s => s.AFechaYYMMDD());    
                foreach (var tipoEntidad in constructor.Model
                    .GetEntityTypes().Where(t => typeof(IYourInterface).IsAssignableFrom(t.ClrType.BaseType))) {
    
                    constructor.Entity(tipoEntidad.Name)
                        .Property("YourPropertyName").HasConversion(convertidor);
                }
    

    或者您也可以将其应用于所有日期属性,请参阅EF CORE 2.1 HasConversion on all properties of type datetime

    【讨论】:

      猜你喜欢
      • 2016-05-05
      • 1970-01-01
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-17
      相关资源
      最近更新 更多