[英]Storing TimeSpan with Entity Framework Codefirst - SqlDbType.Time overflow
我試圖在我的數據庫中植入一些常量:
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 存儲時間跨度? 我真的希望我不需要在這里兩端做一些愚蠢的時間到滴答轉換......
[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
在兩端進行時間到滴答轉換不再是愚蠢的。 不確定他們何時添加它,但實體框架現在將選擇適當的內置轉換器(如果存在)(在本例中為 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 : //docs.microsoft.com/en-us/ef/core/modeling/value-conversions
在這一行:
Span = new TimeSpan(1, 0, 0, 0)
您正在使用此構造函數:
public TimeSpan(int days, int hours, int minutes, int seconds);
因此,您實際上創建了一個大於 24 小時的TimeSpan
因為您將1
傳遞給days
參數,而您的基礎數據庫類型是Time
,它只接受 00:00-23:59 之間的值。
很難判斷您是否真的打算使用 1 天的TimeSpan
,或者這只是一個錯字。
如果您真的想要超過 24 小時的TimeSpan
,我想您必須將您的字段映射到另一種數據庫類型(如SmallDateTime
)。
如果這只是一個錯字錯誤,只需將您的行更改為:
Span = new TimeSpan(1, 0, 0),
如前所述,問題在於 EF 將 TimeSpan 類映射到 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)做一些愚蠢的時間-滴答轉換,如這篇博文中所述。
現在 EF Core 有一個內置的ticks
<=> TimeSpan
轉換。 您所要做的就是:
builder.Property(p => p.SomeTimeSpanProperty)
.HasConversion<long>();
無需實例化新的TimeSpanToTicksConverter
或任何東西。 只要指定類型long
作為一般的參數,你就大功告成了。
有關詳細信息,請參閱EF Core 內置值轉換器
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.