【问题标题】:How to Save TimeSpan value in database in "d.hh:mm:ss" format?如何以“d.hh:mm:ss”格式在数据库中保存 TimeSpan 值?
【发布时间】:2016-02-19 06:03:03
【问题描述】:
TimeSpan timeInDays= new TimeSpan(2,8,8,8);

我想使用 EF 在 DB 中保存“timeInDays”。表格列的类型为“时间”。 它给了我运行时异常,

"SqlDbType.Time 溢出。值 '2.08:08:08' 超出范围。必须 介于 00:00:00.0000000 和 23:59:59.9999999 之间。”

请帮我解决这个问题。

【问题讨论】:

标签: c# sql-server entity-framework


【解决方案1】:

正如@Mainul 所说,time 类型的范围最多为 24 小时。要存储更长的时间段,我建议使用bigint(一个 64 位整数),它可用于直接表示时间跨度值。有关详细信息,请参阅此 QA:What is the correct SQL type to store a .Net Timespan with values > 24:00:00?

如果您无法更改表架构,那么您将不得不截断数据,一种方法是通过在保存到数据库之前向右移动(然后在加载时向左移动)来丢失不太重要的位,但这会很混乱:

默认情况下,SQL Server 中的 time 类型是 time(7)(精度为 7 个十进制数字),它使用 5 个字节,请参见此处:https://msdn.microsoft.com/en-us/library/bb677243.aspx - 所以我们需要转换时间跨度的二进制表示(“ticks "),它使用 8 个字节,向右移动 3 个字节(得到 5 个字节),即 24 位。如下图:

TimeSpan tick value (64-bits): 0x01 0x23 0x45 0x67 0x89 0xAB 0xCD 0xEF
SQL Server time field        :                0x01 0x23 0x45 0x67 0x89

由于 TimeSpan Tick 将它们的最高有效位存储在左侧,这意味着我们将丢失的三个字节 (0xAB 0xCD 0xEF) 代表我们可以承受的不值得担心的一小部分一秒的丢失。当我们从 DB 中加载数据并将其左移 3 个字节时,它看起来像这样(注意三个 0x00 0x00 0x00 字节丢失了它们的值):

TimeSpan tick value (64-bits): 0x01 0x23 0x45 0x67 0x89 0x00 0x00 0x00

保存:

TimeSpan tooBig = new TimeSpoan( 2, 8, 8, 8 );
Int64 tooBigBits = tooBig.Ticks;
Int64 truncated = tooBigBits >> 24;
TimeSpan temp = TimeSpan.FromTicks ( truncated );

yourDbEntity.timeValue = temp;

加载中:

TimeSpan temp = yourDbEntity.timeValue;
Int64 truncated = temp.Ticks;
Int64 adjusted = truncated << 24;
TimeSpan actual = TimeSpan.FromTicks( adjusted );

yourDbEntity.timeValue = actual;

【讨论】:

    【解决方案2】:

    在 T-SQL 中,时间类型列定义一天中的某个时间。时间没有 时区感知并基于 24 小时制。 https://msdn.microsoft.com/en-us/library/bb677243.aspx

    您的 TimeSpan() 方法返回时间,包括大于 24 小时值的日期值。 你可以做的是,保存没有天值的时间值。

    编辑:如果您想从当前 TimeSpan 中减去天值。

    new TimeSpan(timeInDays.Hours, timeInDays.Minutes, timeInDays.Seconds)

    【讨论】:

      【解决方案3】:

      您可以将您的时间作为DateTime (02.01.0001 08:08:08) 存储在数据库中,并且仍然将时间用于您的项目

      public class Task
      {
          [NotMapped] 
          public TimeSpan Duration
          {
              get { return Duration2 - DateTime.MinValue; }
              set { Duration2 = DateTime.MinValue + value; }
          }
      
          public DateTime Duration2 { get; set; }
      }
      

      这样做的缺点是不能基于Duration进行数据库查询

      var tasks = from t in tasks where t.Duration > TimeSpan.FromHours(50);
      

      但你必须使用

      var duration = DateTime.MinValue + TimeSpan.FromHours(50);
      var tasks = from t in tasks where t.Duration2 > duration;
      

      或者您可以使用相同的概念在数据库中存储秒而不是日期值。

      【讨论】:

      • 应该是 DateTime2。而在 EF 查询中,DateTime.MinValue + TimeSpan.FromHours() 部分应该首先存储在一个变量中。
      • @GertArnold 不,它不应该是 DateTime2,我们谈论的是 .NET DateTypes。我将代码更改为首先将值分配给变量。
      猜你喜欢
      • 1970-01-01
      • 2017-06-08
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2018-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多