用Dapper获取UTC时间作为UTC
我正在使用Dapper将我的实体映射到SQL Server CE。 如果我用Kind=Utc
保存DateTime
,当我读到它时,我得到了Kind=Unspecified
的DateTime
,这会导致所有types的问题。
例:
var f = new Foo { Id = 42, ModificationDate = DateTime.UtcNow }; Console.WriteLine("{0} ({1})", f.ModificationDate, f.ModificationDate.Kind); connection.Execute("insert into Foo(Id, ModificationDate) values(@Id, @ModificationDate)", f); var f2 = connection.Query<Foo>("select * from Foo where Id = @Id", f).Single(); Console.WriteLine("{0} ({1})", f2.ModificationDate, f2.ModificationDate.Kind);
这段代码给出了以下输出:
20/09/2012 10:04:16 (Utc) 20/09/2012 10:04:16 (Unspecified)
我知道我应该使用DateTimeOffset
,但不幸的是SQL CE不支持这种types。
有没有解决方法? 我能告诉Dapper假设所有date都有DateTimeKind.Utc
吗? 更一般地说,我有什么select来定制映射?
编辑:我目前的解决方法是修补后的细节已经物化结果的date,但它的气味…
var results = _connection.Query<Foo>(sql, param).Select(PatchDate); ... static Foo PatchDate(Foo f) { if (f.ModificationDate.Kind == DateTimeKind.Unspecified) f.ModificationDate = DateTime.SpecifyKind(f.ModificationDate, DateTimeKind.Utc); return f; }
看着小巧的代码。 除非我的版本过时了,对于datetime(映射到DbType.DateTime)这样的值types,dapper只是简单的从IDataReader对象中强制转换。
Pseudo:yield return(DateTime)IDataReader.GetValue(0);
这是Datetime中的一些generics代码和lambdaexpression式的具体情况。
AFAIK,SQLdate时间永远不会存储偏移量/时区,因此在您存储和获取任何date时间types总是会说“未指定”。
所以,要干净地做到这一点,你可以触摸短小精悍的内部:
这是一个痛苦,因为你不得不触摸一个大的IL生成方法(DataRow解串器),并把它放在DateTime的情况下。
要么
只是把一个setter的UTC时间的道具上的问题(这是有点对POCO,但相对理智):
class Foo { private DateTime _modificationDate; public DateTime ModificationDate { get { return _modificationDate; } set { _modificationDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); } } //Ifs optional? since it's always going to be a UTC date, and any DB call will return unspecified anyways }
为寻求简单修复的人添加这个答案。 现在可以在Dapper中添加SqlMapper.TypeHandler了。
添加这个类来将数据库中的值转换为指定为UTC的types的date时间。
public class DateTimeHandler : SqlMapper.TypeHandler<DateTime> { public override void SetValue(IDbDataParameter parameter, DateTime value) { parameter.Value = value; } public override DateTime Parse(object value) { return DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc); } }
然后在我的Web API的Global.asax文件中,将types处理程序添加到Dapper中。
SqlMapper.AddTypeHandler(new DateTimeHandler());
如果您需要确保始终将date作为UTC插入,则可以使用SetValue方法:
parameter.Value = DateTime.SpecifyKind(value, DateTimeKind.Utc);
如果你使用来源(而不是nuget)的Dapper,你可以调整代码,始终强制UTC的DateTimeKind。 一个更可configuration的选项可能是为DateTime属性值创build一个新的属性,使您可以指定date时间types作为一个提示精简。 Dapper可以用这个属性查找DateTime属性,find的时候可以用它来指定ORM映射期间的DateTimetypes。 这可能是一个不错的核心小巧玲珑function,因为你不是唯一一个这个问题:)