使用实体框架Codefirst存储TimeSpan - SqlDbType.Time溢出

SB2*_*055 24 .net c# entity-framework ef-code-first

我正在尝试将一些常量添加到我的数据库中:

context.Stages.AddOrUpdate(s => s.Name,
                                   new Stage()
                                   {
                                       Name = "Seven",
                                       Span = new TimeSpan(2, 0, 0),
                                       StageId = 7
                                   });
context.Stages.AddOrUpdate(s => s.Name,
                                   new Stage()
                                   {
                                       Name = "Eight",
                                       Span = new TimeSpan(1, 0, 0, 0),
                                       StageId = 8
                                   });
Run Code Online (Sandbox Code Playgroud)

这是我的用于EF Codefirst Migrations的Seed()函数.它在第八阶段失败,具体如下:

System.Data.UpdateException:更新条目时发生错误.有关详细信息,请参阅内部异常 ---> System.OverflowException:SqlDbType.Time溢出.值'1.00:00:00'超出范围.必须在00:00:00.0000000和23:59:59.9999999之间.

为什么我无法使用EF存储时间跨度?我真的希望我不需要在这两端做一些愚蠢的时间转换...

Shi*_*mmy 33

    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("Property '" + nameof(Duration) + "' should be used instead.")]        
    public long DurationTicks { get; set; }

    [NotMapped]
    public TimeSpan Duration
    {
#pragma warning disable 618
      get { return new TimeSpan(DurationTicks); }
      set { DurationTicks = value.Ticks; }
#pragma warning restore 618
    }
Run Code Online (Sandbox Code Playgroud)

更新

现在,这可以通过使用价值转换的 EF Core 2.1实现.

builder.Entity<Stage>()
    .Property(s => s.Span)
    .HasConversion(new TimeSpanToTicksConverter()); // or TimeSpanToStringConverter
Run Code Online (Sandbox Code Playgroud)

  • 对于那些被pragma警告抑制困惑的人来说,这可能会有所帮助:http://stackoverflow.com/questions/968293/c-sharp-selectively-suppress-custom-obsolete-warnings (4认同)
  • 很好的答案,可能值得为持续时间添加[NotMapped]属性 (3认同)
  • 注意`HasConversion &lt;TimeSpanToTicksConverter&gt;();`不是**注册转换器的正确方法!您需要传递一个实例,而不是像这样的泛型类型:`HasConversion(new TimeSpanToTicksConverter());` (2认同)

小智 11

在两端进行时间到滴答转换不再是愚蠢的。不确定他们何时添加它,但实体框架现在将选择适当的内置转换器(如果存在)(在本例中为 TimeSpanToTicksConverter)。您需要做的就是向实体类添加一个属性,实体框架将自动为 SQL 表中的列提供与 TimeSpan 类相同的范围。

public class Stage
{
    public string Name { get; set; }

    [Column(TypeName = "bigint")]
    public TimeSpan Span { get; set; }

    public int StageId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我确信 bigint 不是 TimeSpan 的默认列类型,以实现人类可读性和向后兼容性,但这似乎是一个非常完美的解决方案。

我希望这可以帮助任何人在六年后遇到这个问题。

文档:https : //docs.microsoft.com/en-us/ef/core/modeling/value-conversions


Ami*_*adi 10

现在 EF Core 具有内置的ticks<=>TimeSpan转换。您所要做的就是:

builder.Property(p => p.SomeTimeSpanProperty)
    .HasConversion<long>();
Run Code Online (Sandbox Code Playgroud)

无需实例化新的TimeSpanToTicksConverter或任何东西。只需将类型指定long为通用参数即可。

有关详细信息,请参阅EF Core 内置值转换器


hai*_*770 7

在这一行:

Span = new TimeSpan(1, 0, 0, 0)
Run Code Online (Sandbox Code Playgroud)

你正在使用这个构造函数:

public TimeSpan(int days, int hours, int minutes, int seconds);
Run Code Online (Sandbox Code Playgroud)

因此,您实际创建的传输TimeSpan时间超过了24小时,而您的基础数据库类型只接受00:00-23:59之间的值.1daysTime

很难说你是否真的想要有TimeSpan一天,或者只是一个错字.

如果你真的想要TimeSpan超过24小时,我想你必须将你的字段映射到另一个数据库类型(如SmallDateTime).

如果这只是一个拼写错误,只需将您的行更改为:

Span = new TimeSpan(1, 0, 0),
Run Code Online (Sandbox Code Playgroud)

  • 从什么时候开始,逻辑时间限制为24小时?特别愚蠢的是`TimeSpan`类[支持多天](https://msdn.microsoft.com/en-us/library/85ydwftb%28v=vs.110%29.aspx). (10认同)
  • 究竟.DB类型映射是完全错误的,因为`TimeSpan`数据不会进入db类型`Time`.这听起来像个错误. (10认同)
  • EF Core 脚手架*自动*将 TimeSpans 转换为 Time。IMO 这是一个框架错误。 (3认同)
  • @Diederik,答案中没有任何地方说'TimeSpan' 限制为24 小时,映射的数据库列('Time')受到限制。这完全是关于错误的映射,而不是“TimeSpan”限制(这肯定支持超过 1 天)。 (2认同)