Сохранение Nodatime Instant в SQL Server с помощью ServiceStack/OrmLite

Я использую NodaTime Instant для хранения даты/времени в своих DTO с ServiceStack. Я указал тип SQL в DTO как datetimeoffset, и ServiceStack правильно создает таблицу с этим типом. Однако при сохранении я получаю InvalidCastException.

Простой пример:

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

В сервисе:

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

Конкретной ошибкой является InvalidCastException с подробным описанием Не удалось преобразовать значение параметра из Instant в 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);
    }
}

Затем я зарегистрировал его в своем файле AppHost.cs:

Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(Settings.Default.LocalSqlConnectionString, SqlServerDialect.Provider));
SqlServerDialect.Provider.RegisterConverter<Instant>(new SqlServerInstantConverter());

Не забудьте переопределить FromDbType. Сначала я забыл об этом, и поле не выводилось.

Еще одно предостережение: поскольку ServiceStack хочет локализовать все даты, мне пришлось использовать информацию в этом ответе, чтобы перевести все даты в DateTimeKind.Local


person Josh Anderson    schedule 05.09.2015    source источник


Ответы (1)


[CustomField] просто сообщает OrmLite, какое определение столбца использовать при создании таблицы, т. е. не указывает, как OrmLite должен обрабатывать неизвестные типы.

Вы можете поддерживать новые типы полей, зарегистрировав конвертер пользовательского типа, который теперь доступно в последней версии v4.0.44.

person mythz    schedule 05.09.2015
comment
Всегда впечатлялась твоей отзывчивостью, @mythz! Это сработало как шарм. Я обновлю свой вопрос с кодом. - person Josh Anderson; 05.09.2015
comment
К вашему сведению. Недавно я написал расширение для поддержки Noda Time in Dapper. Вероятно, можно было бы написать что-то подобное для OrmLite, используя пользовательские преобразователи типов. - person Matt Johnson-Pint; 05.09.2015