【问题标题】:Using OffsetDateTime with NHibernate在 NHibernate 中使用 OffsetDateTime
【发布时间】:2015-12-24 12:24:32
【问题描述】:

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

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

2015-12-24 11:18+01:002015-12-24 10:18+00:00 在 SQL Server 中被视为相等,但在 NodaTime 中不相等。

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

【问题讨论】:

  • 首先,你想做什么?如果您将两个值都转换为 NodaTime 瞬间,它们相等 - 它们确实指的是同一个瞬间。你真的希望它们表现出不同的价值吗?
  • 第二,NHibernat 映射你的类到数据库。您不能使用数据库类型不支持的语义。 LINQ 或任何 ORM 不会改变数据库的功能,它们只是使对象和表之间的映射更容易。任何其他用途都是严重的气味
  • 我想在我的模型中使用 NodaTime 的 OffsetDateTime 类型并将它们映射到 SQL Server 的 DateTimeOffset 或 2 列,DateTime 存储 UTC 值和偏移量。跨度>

标签: nhibernate nodatime


【解决方案1】:

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

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

也许有人应该编写一个 NHibernate-NodaTime 集成包来简化这个过程。考虑到我之前为RavenDBDapper 做过这个,我会考虑它。 :)

抱歉,我没有更好的实际“这样做”答案。


更新

我开始研究这个,并成功地为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。 :)

【讨论】:

  • @JonSkeet(如果你正在阅读这篇文章)请注意没有OffsetDateTime 的默认比较器会如何导致在这样的上下文中出现问题。另外,请注意,此处无法实现按 本地时间 进行比较,因为最终 LINQ 将被转换为 SQL 语句,并且 SQL 总是 比较 datetimeoffset 类型他们的 UTC 等效值。
  • 是的,我正在阅读 :) 那么你认为OffsetDateTime 应该有一个即时的默认比较,比如 SQL 吗?请注意,它与相等性不兼容,它将比较偏移量和瞬时值...... SQL 对此做了什么?
  • 我通过使用自定义LinqToHqlGeneratorsRegistry 并处理ToInstant 方法得到了该概念gist.github.com/chilversc/d1ba1fdbae58d8a13704 的工作实现。在我的实现中,我使用复合用户类型作为其具有单独的 UTC 日期/时间和偏移列的遗留数据库。
  • @JonSkeet MSSQL 将DateTimeOffset 按其即时时间排序(即忽略偏移量)并认为两个DateTimeOffsets 相同,如果它们是相同的时间。拥有一个比较器可以让 Linq 和 MSSQL 的使用变得更简单,就像你可以拥有 query.OrderBy(x =&gt; x.CreateAt) 一样。唯一我不确定的是有多少代码假设当CompareTo == 0 然后Equals == true
  • @ChrisChilvers:我们已经有了OffsetDateTime.Comparer.Instant,如 Matt 所示;你可以使用query.OrderBy(x =&gt; x.CreateAt, OffsetDateTime.Comparer.Instant)。如果您的意思是实现IComparable&lt;T&gt;...我会考虑更多。我希望Equals 仍然考虑偏移量,但我可以看到自然排序如何仅在瞬间完成。正如你所说,让平等和排序做不同的事情有点奇怪。
猜你喜欢
  • 2019-03-16
  • 2023-01-15
  • 2018-10-06
  • 2017-09-18
  • 1970-01-01
  • 2018-02-19
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多