用Dapper获取UTC时间作为UTC

我正在使用Dapper将我的实体映射到SQL Server CE。 如果我用Kind=Utc保存DateTime ,当我读到它时,我得到了Kind=UnspecifiedDateTime ,这会导致所有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,因为你不是唯一一个这个问题:)