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

b1uwtaje  于 2023-06-25  发布在  .NET
关注(0)|答案(5)|浏览(130)

我正在尝试在DB中添加一些常量:

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
                                   });

这是在我的EF Codefirst迁移的Seed()函数中。它在第八阶段失败,出现以下情况:
System.Data.UpdateException:更新条目时出错。有关详细信息,请参见内部异常。- --> System. OverflowException:SqlDbType。时间溢出。值“1.00:00:00”超出范围。必须介于00:00:00.0000000和23:59:59.999999之间。
为什么我不能使用EF存储时间跨度?我真的希望我不需要做一些愚蠢的时间到刻度转换两端在这里。

pbossiut

pbossiut1#

[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
    }

更新

从EF Core 2.1开始,使用Value Conversion就可以实现这一点。

builder.Entity<Stage>()
    .Property(s => s.Span)
    .HasConversion(new TimeSpanToTicksConverter()); // or TimeSpanToStringConverter
eqqqjvef

eqqqjvef2#

在两端进行时间到刻度的转换不再是愚蠢的。不确定他们是什么时候添加的,但实体框架现在将选择适当的内置转换器(如果存在)(在本例中是TimeSpanToTicksConverter)。你所需要做的就是给你的实体类添加一个属性,实体框架会自动给予SQL表中的列一个与TimeSpan类相同的范围。

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

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

    public int StageId { get; set; }
}

我确信bigint不是TimeSpan的默认列类型,以便于可读性和向后兼容,但这似乎是一个非常完美的解决方案。
我希望这对六年后遇到这个问题的人有所帮助。
文件:https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions

oxalkeyp

oxalkeyp3#

在这一行中:

Span = new TimeSpan(1, 0, 0, 0)

您使用的是以下构造函数:

public TimeSpan(int days, int hours, int minutes, int seconds);

因此,实际上您创建的TimeSpan大于24小时,因为您将1传递给days参数,而您的基础数据库类型是Time,它只接受00:00-23:59之间的值。
很难判断你是否真的打算用1天的TimeSpan,或者它只是一个打字错误。
如果你真的想要一个大于24小时的TimeSpan,我想你必须把你的字段Map到另一个数据库类型(比如SmallDateTime)。
如果只是一个打字错误,只需将您的行改为:

Span = new TimeSpan(1, 0, 0),
nvbavucw

nvbavucw4#

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

builder.Property(p => p.SomeTimeSpanProperty)
    .HasConversion<long>();

不需要示例化一个新的TimeSpanToTicksConverter或任何东西。只需指定类型long作为泛型参数,就完成了。
有关更多信息,请参阅EF Core内置价值转换器

a2mppw5e

a2mppw5e5#

如前所述,问题在于EF将TimeSpan类Map到Time,该时间被限制为24小时。
如果您需要存储超过24小时的时间跨度,我建议使用以下两种方法之一:

**1)**为一个时间跨度的不同元素创建一个具有int属性的TimeSpan实体,类似于:

public class Timespan
{
    public Int64 Id { get; set; }

    public Int16 Years { get; set; }

    public int Months { get; set; }

    public Int64 Days { get; set; }

    public Int64 Hours { get; set; }

    public Int64 Minutes { get; set; }
}

只需将适用实体中的外部引用添加到自定义Timespan实体中即可。

**2)**做一些愚蠢的时间到滴答的转换,如blog post中所解释的。

相关问题