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'.'
但是我在使用 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 按预期工作。
我让 ServiceStack OrmLite (5.1.1) 创建 table,并保留包含 TimeSpan 的对象:
// ...
public TimeSpan _Jobs_VehicleNotificationTime { get; set; }
// ...
当我试图读回它时,我得到这个错误:
System.InvalidCastException: 'Invalid cast from 'System.Int64' to 'System.TimeSpan'.'
但是我在使用 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 按预期工作。