使用 ServiceStack / OrmLite 在 SQL Server 中持久化 Nodatime Instant

Jos*_*son 5 c# sql-server servicestack nodatime ormlite-servicestack

我在InstantServiceStack 的 DTO 中使用 NodaTime进行日期/时间存储。我已将 DTO 中的 SQL 类型指定为datetimeoffset,ServiceStack 正确创建了具有该类型的表。但是,在保存时,我得到一个InvalidCastException.

简单的例子:

public class ItemWithInstant
{
    public int Id { get; set; }
    public string Name { get; set; }
    [CustomField("DateTimeOffset")
    public Instant DateCreated { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在服务中:

public object Post(CreateItemWithInstant request)
{
    var dto = request.ConvertTo<ItemWithInstant>();
    Db.Save(dto); // ERROR here
    return dto;
}
Run Code Online (Sandbox Code Playgroud)

具体的错误是一个InvalidCastException带有Failed to convert parameter value from an Instant to a String 的详细信息。

不知道为什么当数据库类型为DateTimeOffset. 我是否需要告诉 ServiceStack 如何将值转换为适用于 SQL 类型的值?

更新

感谢@mythz 的回答,我创建了一个自定义转换器。我也最终DATETIME2选择了 SQL 数据类型(不要认为这有什么区别):

public class SqlServerInstantToDatetimeConverter : OrmLiteConverter
{
    public override string ColumnDefinition { get { return "DATETIME2"; } }

    public override DbType DbType { get { return DbType.DateTimeOffset; } }

    public override object ToDbValue(Type fieldType, object value)
    {
        var instantValue = (Instant) value;
        return instantValue.ToDateTimeUtc();
    }

    public override object FromDbValue(Type fieldType, object value)
    {
        var datetimeValue = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
        return Instant.FromDateTimeUtc(datetimeValue);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我在我的AppHost.cs文件中注册了它:

Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(Settings.Default.LocalSqlConnectionString, SqlServerDialect.Provider));
SqlServerDialect.Provider.RegisterConverter<Instant>(new SqlServerInstantConverter());
Run Code Online (Sandbox Code Playgroud)

不要忘记FromDbType覆盖。我最初忘记了它并且该字段没有被输出。

另一个警告——由于 ServiceStack 想要本地化所有日期,我不得不使用此答案中的信息将所有日期强制为 DateTimeKind.Local

myt*_*thz 4

[CustomField]只是告诉 OrmLite 在创建表时要使用什么列定义,即它不提供任何有关 OrmLite 应如何处理未知类型的指示。

您可以通过注册最新 v4.0.44 版本中提供的自定义类型转换器来支持新字段类型。