如何将大于24小时的TimeSpan映射到SQL Server Code First?

43

我正在尝试将一个TimeSpan Code First属性映射到SQL Server上。Code First似乎将其创建为SQL中的Time(7)类型。但是.Net中的TimeSpan可以处理超过24小时的时间段,我需要存储超过24小时的事件长度。使用Code First,最好的处理方法是什么?

3个回答

36

根据我的先前的问题,关于如何在SQL中存储TimeSpan,我被建议将其存储为秒或滴答等。最终我没有将TimeSpan列映射到数据库中,因为SQL Server中没有相应的数据类型。我只是创建了第二个字段,将TimeSpan转换为滴答并将其存储在数据库中。然后我防止了TimeSpan的存储。

public Int64 ValidityPeriodTicks { get; set; }
 
[NotMapped]
public TimeSpan ValidityPeriod
{
    get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
    set { ValidityPeriodTicks = value.Ticks; }
}
如果您想在EF Core中执行此操作,那么使用值转换会更清晰一些。在2.1版本中,您可以使用值转换和TimeSpanToTicksConverter将TimeSpan映射到数据库中的ticks上,这样做非常值得考虑(假设其他功能符合需求)-可以在Framework 4.7项目中使用它,因此不需要切换到.Net Core。

2
这种方法可能会导致次优的查询,当有人不知道或忘记 ValidityPeriod 是一个 NotMapped 属性时。如果它在 LINQ where 查询中被使用,EF 不会抱怨,它只会拉取集合并迭代它。因此,人们可以使用老式的 Get/Set 访问器来明确表示它们不应该用于查询。 - StanislawSwierc
同意,我在我的解决方案中调整了代码,以便实现更清晰。 - GraemeMiller
4
使用扩展方法来获取或设置值,这样可以减少误解。 - deerchao
3
根据StanislawSwierc的评论,我们可以考虑这样做:不要创建一个NotMapped属性,而是创建一个"GetValidityPeriod(): TimeSpan"方法和一个"SetValidityPeriod(period: TimeSpan): void"方法。这样,它就会明确地未映射,并且明显不应在Linq查询中使用。 - Jerther

3

1
是的,除了我的答案之外,我从未找到其他方法。EF 似乎只是偶尔将其映射到 SQL Server 时间数据类型,这显然是不匹配的。 - GraemeMiller

1
首先,MVC与这个问题无关。它完全涉及EF Code First和SQL Server,因此它是一个数据访问层(DAL)问题。
一种解决方案是在实体配置中提供自定义列类型,类似于这样:
modelBuilder
.Entity<MyClass>()
.Property(c => c.MyTimeSpan)
.HasColumnType("whatever sql type you want to use");

好的。你想使用任何类型的SQL都可以,我关心的是什么。将 .Net TimeSpan 映射到 SQL Server 字段的标准方法是什么? - GraemeMiller
我认为这已经足够清楚了。 HasColumnType 方法的字符串参数必须包含您在 SQL 脚本或表设计器中声明的 SQL 类型,例如 nvarchar(50) 或 bit 或任何您需要且与您正在使用的 .Net 数据类型兼容的内容。至于在您特定情况下要使用的确切类型,只需进行实验即可。 - Matteo Mosca
6
我知道如何更改列类型,但这不是问题所在。将 .Net TimeSpan 映射到 SQL 似乎是一个相当常见的问题。我想了解存储 .Net TimeSpan 到 SQL Server 的最佳方式是什么。 - GraemeMiller
那么你的问题与Code First无关,它更像是一个一般性问题。更像是“应该将哪种正确的SQL类型与.Net Timespan相关联”。我给出这样的答案是因为你问了如何在Code First中实现它,而我给了你一个Code First示例。 - Matteo Mosca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接