我试图在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。

您还可以在数据库中调整浮点数的精度。

这不是一个确切的值……但是这样做的好处是它很容易在简单的查询中读取和计算。