我试图在SQL server 2008 R2中存储. net TimeSpan。
EF Code First似乎建议它应该存储为SQL中的时间(7)。
然而。net中的TimeSpan可以处理超过24小时的时间。
在SQL server中存储。net TimeSpan的最佳方法是什么?
我试图在SQL server 2008 R2中存储. net TimeSpan。
EF Code First似乎建议它应该存储为SQL中的时间(7)。
然而。net中的TimeSpan可以处理超过24小时的时间。
在SQL server中存储。net TimeSpan的最佳方法是什么?
当前回答
谢谢你的建议。因为在SQL server中没有对等的。我简单地创建了第二个字段,将TimeSpan转换为tick并将其存储在DB中。然后,我阻止存储TimeSpan
public Int64 ValidityPeriodTicks { get; set; }
[NotMapped]
public TimeSpan ValidityPeriod
{
get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
set { ValidityPeriodTicks = value.Ticks; }
}
其他回答
谢谢你的建议。因为在SQL server中没有对等的。我简单地创建了第二个字段,将TimeSpan转换为tick并将其存储在DB中。然后,我阻止存储TimeSpan
public Int64 ValidityPeriodTicks { get; set; }
[NotMapped]
public TimeSpan ValidityPeriod
{
get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
set { ValidityPeriodTicks = value.Ticks; }
}
有多种方法可以在数据库中表示时间跨度。
time
从SQL Server 2008开始就支持这种数据类型,是存储TimeSpan的首选方式。不需要映射。它也可以很好地处理SQL代码。
public TimeSpan ValidityPeriod { get; set; }
然而,正如在最初的问题中所述,这种数据类型仅限于24小时。
日期时间偏移量
datetimeoffset数据类型直接映射到System.DateTimeOffset。它用于表示datetime/datetime2与UTC之间的偏移量,但您也可以将它用于TimeSpan。
但是,由于数据类型暗示了一种非常特定的语义,因此还应该考虑其他选项。
日期,时间
一种方法可能是使用datetime或datetime2类型。这在需要直接处理数据库中的值的场景中是最好的。用于视图、存储过程或报表。缺点是您需要从日期中减去DateTime(1900,01,01,00,00,00)值,以获得业务逻辑中的时间间隔。
public DateTime ValidityPeriod { get; set; }
[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
get { return ValidityPeriod - DateTime(1900,01,01,00,00,00); }
set { ValidityPeriod = DateTime(1900,01,01,00,00,00) + value; }
}
长整型数字
另一种方法可能是将TimeSpan转换为tick并使用bigint数据类型。但是,这种方法有一个缺点,在SQL查询中使用起来很麻烦。
public long ValidityPeriod { get; set; }
[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
get { return TimeSpan.FromTicks(ValidityPeriod); }
set { ValidityPeriod = value.Ticks; }
}
转换为(N)
这对于值应该由人类可读的情况是最好的。您还可以在SQL查询中使用CONVERT(datetime, ValidityPeriod)函数来使用这种格式。根据所需的精度,您将需要8到25个字符。
public string ValidityPeriod { get; set; }
[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
get { return TimeSpan.Parse(ValidityPeriod); }
set { ValidityPeriod = value.ToString("HH:mm:ss"); }
}
奖励:时间段和持续时间
使用字符串,还可以存储NodaTime数据类型,特别是Duration和Period。前者基本上与TimeSpan相同,而后者则考虑到某些日和月比其他日和月更长或更短。一月有31天,二月有28或29天;由于日光节约时间,有些日子变长或变短)。在这种情况下,使用TimeSpan是错误的选择。
你可以使用这段代码转换period:
using NodaTime;
using NodaTime.Serialization.JsonNet;
internal static class PeriodExtensions
{
public static Period ToPeriod(this string input)
{
var js = JsonSerializer.Create(new JsonSerializerSettings());
js.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
var quoted = string.Concat(@"""", input, @"""");
return js.Deserialize<Period>(new JsonTextReader(new StringReader(quoted)));
}
}
然后像这样使用它
public string ValidityPeriod { get; set; }
[NotMapped]
public Period ValidityPeriodPeriod
{
get => ValidityPeriod.ToPeriod();
set => ValidityPeriod = value.ToString();
}
我真的很喜欢NodaTime,它经常把我从棘手的bug和很多头痛中拯救出来。这里的缺点是不能在SQL查询中使用它,需要在内存中进行计算。
CLR自定义类型
您还可以选择直接使用自定义数据类型和支持自定义TimeSpan类。有关详细信息,请参见CLR用户定义类型。
这里的缺点是数据类型可能不能很好地使用SQL报表。此外,某些版本的SQL Server (Azure, Linux,数据仓库)不受支持。
值转换
从EntityFramework Core 2.1开始,你可以选择使用值转换。
然而,当使用这个时,EF将不能将许多查询转换为SQL,导致查询在内存中运行;潜在地向您的应用程序传输大量数据。
因此,至少现在,最好不要使用它,而只是用Automapper映射查询结果。
现在,使用EF Core,您可以在AppDbContext中透明地转换数据类型
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// i.e. Store TimeSpan as string (custom)
modelBuilder
.Entity<YourClass>()
.Property(x => x.YourTimeSpan)
.HasConversion(
timeSpan => timeSpan.ToString(), // To DB
timeSpanString => TimeSpan.Parse(timeSpanString) // From DB
);
// i.e. Store TimeSpan as string (using TimeSpanToStringConverter)
modelBuilder
.Entity<YourClass>()
.Property(x => x.YourTimeSpan)
.HasConversion(new TimeSpanToStringConverter());
// i.e. Store TimeSpan as number of ticks (custom)
modelBuilder
.Entity<YourClass>()
.Property(x => x.YourTimeSpan)
.HasConversion(
timeSpan => timeSpan.Ticks, // To DB
timeSpanString => TimeSpan.FromTicks(timeSpanString) // From DB
);
// i.e. Store TimeSpan as number of ticks (using TimeSpanToTicksConverter)
modelBuilder
.Entity<YourClass>()
.Property(x => x.YourTimeSpan)
.HasConversion(new TimeSpanToTicksConverter());
}
我将它作为BIGINT存储在数据库中,我将存储tick的数量(例如。时间间隔。蜱虫属性)。
这样,如果我想在检索时获得一个TimeSpan对象,我只需执行TimeSpan. fromticks (value),这很简单。
我会存储时间跨度。然后使用Timespan.FromSeconds(TotalSeconds)检索它。
根据你需要的分辨率,你可以使用TotalMilliseconds, TotalMinutes, TotalDays。
您还可以在数据库中调整浮点数的精度。
这不是一个确切的值……但是这样做的好处是它很容易在简单的查询中读取和计算。