ServiceStack.OrmLite:使用 Untyped API 读回 TimeSpan 导致 InvalidCastException

ServiceStack.OrmLite: Reading back a TimeSpan using Untyped API results in InvalidCastException

我让 ServiceStack OrmLite (5.1.1) 创建 table,并保留包含 TimeSpan 的对象:

// ...
public TimeSpan _Jobs_VehicleNotificationTime { get; set; }
// ...

当我试图读回它时,我得到这个错误:

System.InvalidCastException: 'Invalid cast from 'System.Int64' to 'System.TimeSpan'.'

价值is persisted as a long似乎:

但是我在使用 FromObjectDictionary 方法时得到了这个:

错误是:

   at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
   at ServiceStack.PlatformExtensions.ObjectDictionaryFieldDefinition.SetValue(Object instance, Object value)
   at ServiceStack.PlatformExtensions.FromObjectDictionary(IReadOnlyDictionary`2 values, Type type)
   at tWorks.Core.CoreServerCommons.Handlers.OrmLiteDbHandler.<>c__DisplayClass65_1.<ReadObjects>b__1(Dictionary`2 x) in D:\[GIT]\Core\CoreServerCommons\Handlers\DbHandlers\OrmLite\OrmLiteDbHandler.cs:line 577

这是一个错误还是我遗漏了什么?

TimeSpan 在 OrmLite 中存储为整数列,以确保它们在所有支持的 RDBMS 中保持精度和行为。如果您使用对象字典中的动态结果集检索它,那么它将只能 return 尚未通过 OrmLite 转换器的数据 reader 值将其转换回 TimeSpan,在这种情况下,您将无法在此处使用 ServiceStack.Text 的 FromObjectDictionary() 通用扩展方法,它不使用 OrmLite 的转换器。

我想我已经解决了这个问题。也许@mythz 可以告诉我这是否完全错误,但它似乎有效:

实现你自己的TimeSpanAsIntConverter

我首先否定了这个想法,因为我错误地将 Mythz 解释为转换器不相关或如果使用 Untyped API 则不会执行。当我实现 TimeSpan 转换器时,它按预期工作:

namespace Commons
{
    public class MyTimeSpanConverter : TimeSpanAsIntConverter
    {
        public override string ColumnDefinition => "TIME";
        public override DbType DbType => DbType.Time;

        public override object ToDbValue(Type fieldType, object value)
        {
            TimeSpan timespan = (TimeSpan)value;
            return timespan;
        }

    }
}

然后,当使用该转换器时,table 是使用 TIME 类型而不是 bigint 类型正确创建的,并且在持久化时,一切看起来都正常:

测试代码:

    public void Test()
    {
        Customer c = new Customer() { Username = "TED ÅÄÖ", DeletedTime = DateTime.MaxValue, MyTimeSpan = new TimeSpan(1, 30, 0) };
        CoreObject co = c;
        long id;
        using (IDbConnection db = _dbFactory.Open())
        {
            var typedApi = db.CreateTypedApi(co.GetType());
            id = typedApi.Insert(co, selectIdentity: true);
        };

        using (IDbConnection db = _dbFactory.Open())
        {
            string tableName = co.GetType().GetModelMetadata().ModelName;
            List<Dictionary<string, object>> results = db.Select<Dictionary<string, object>>($"SELECT * FROM {tableName} where id={id}");
            List<CoreObject> coreObjects = results.Map(x => (CoreObject)x.FromObjectDictionary(co.GetType()));
        }
    }

结果:

这似乎至少为我解决了这个问题 - 我的 TimeSpans 按预期工作。