在 NHibernate 中使用 OffsetDateTime

Using OffsetDateTime with NHibernate

我正在尝试将 NodaTime 的 OffsetDateTime 类型映射到 SQL 服务器,但我不确定如何解决 NodaTime 的 OffsetDateTime 和 SQL 服务器之间的阻抗DateTimeOffset 种类型。

我遇到的主要问题是让 LINQ 支持正常工作,因为 OffsetDateTime 没有比较运算符,例如 <。这些系统在如何处理平等方面也有所不同。 NodaTime 同时考虑即时和偏移量,而 SQL 服务器只考虑即时。

2015-12-24 11:18+01:002015-12-24 10:18+00:00在SQL服务器中被认为是相等的,但在NodaTime中不相等。

我考虑过使用 ICompositeUserType 将 UTC date/time 和偏移量存储在单独的列中(类似于之前的 SQL Server 2008)但是 OffsetDateTime 没有一个 UTC/Instant 属性。因此,我看不到如何让 LINQ 查询中的 date.ToInstant() 正确映射到 ICompositeUserType.

中的 属性

OffsetDateTime 应映射到 SQL 服务器 datetimeoffset。 NHibernate 通过 IUserType as described in this article 对自定义类型映射的支持对于完成这项工作至关重要。

虽然OffsetDateTime没有直接实现IComparable,但是可以用OffsetDateTime.Comparer.Instant来比较。这在 LINQ 查询中可能仍然难以使用,但这是探索的一种途径。

有人可能应该编写一个 NHibernate-NodaTime 集成包来使这更简单。考虑到我之前为 RavenDB and for Dapper 做过这个,我会考虑它。 :)

抱歉,我没有更好的实际 "do this" 答案给你。


更新

我开始研究这个,并成功地为 OffsetDateTime 构建了一个 IUserType,但它不适用于比较运算符 - 由于您描述的原因。我相信解决方案涉及扩展 linq 提供程序,类似于 in this blog post 中描述的技术。我还没有完整的工作示例,但我会在此处更新。

最终,您将无法编写:

session.Query<Foo>().Where(x => x.SomeODT > value)

因为OffsetDateTime没有比较运算符,所以无法编译。

相反,应扩展 LINQ 提供程序以支持如下内容:

session.Query<Foo>().Where(x => OffsetDateTime.Comparer.Instant.Compare(x.SomeODT, value) > 0)

或者可能更简洁:

session.Query<Foo>().Where(x => x.SomeODT.ToInstant() > value.ToInstant())

或者两者兼而有之。两者都可以编译,但如果没有 LINQ 提供程序的适当支持就会抛出异常。


第二次更新

有人打败了我。 NHibernate 现在有一组扩展来支持 Noda Time 数据类型 in this project。 :)