33

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

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.Time 溢出。值“1.00:00:00”超出范围。必须介于 00:00:00.0000000 和 23:59:59.9999999 之间。

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

4

5 回答 5

48
    [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
于 2015-01-20T04:04:56.063 回答
12

在两端进行时间到滴答声的转换不再是愚蠢的。不确定他们何时添加它,但 Entity Framework 现在将选择适当的内置转换器(如果存在)(在本例中为 TimeSpanToTicksConverter)。您需要做的就是向您的实体类添加一个属性,Entity Framework 将自动为 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 ://docs.microsoft.com/en-us/ef/core/modeling/value-conversions

于 2019-11-27T18:37:00.647 回答
9

在这一行:

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

您正在使用此构造函数:

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

因此,自传递给参数以来,您实际上创建了TimeSpan超过 24 小时,而您的基础数据库类型仅接受 00:00-23:59 之间的值。1daysTime

很难说你是否真的打算有TimeSpan1 天,或者这只是一个错字。

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

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

Span = new TimeSpan(1, 0, 0),
于 2013-06-16T07:51:20.197 回答
0

如前所述,问题在于 EF 将 TimeSpan 类映射到时间,时间限制为 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)做一些愚蠢的时间到滴答声转换,如这篇文中所述。

于 2014-01-07T10:57:36.653 回答
0

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

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

无需实例化新的TimeSpanToTicksConverter或任何东西。只需将类型指定long为泛型参数,就完成了。

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

于 2021-11-03T15:36:53.197 回答