转换数据库的NHibernate日期格式问题

时间:2018-05-24 21:49:13

标签: sql-server oracle nhibernate nhibernate-mapping

我们有一个使用NHibernate连接到Oracle数据库的应用程序。我的任务是将Oracle数据库转换为SQL Server数据库,以便在数据库之间切换就像更改NHibernate驱动程序一样简单。在我的Oracle DB中,我有一个列定义为TIMESTAMP(6)WITH TIME ZONE。此列已转换为SQL Server datetimeoffset(6)数据类型。我的NHibernate hbm.xml文件中的映射如下所示:

<property name="checkoutDate" type="DateTime">
      <column name="CHECKOUT_DATE" sql-type="TIMESTAMP(6) WITH TIME ZONE" not-null="false" />
    </property>

通过这种映射,当我在SSMS中运行查询时,我能够在表格中插入一个日期:2018-05-24 10:48:17.000000 +00:00。但是,当我尝试查询此表时,我得到两个例外:

FormatException: Input string '5/24/2018 10:48:17 +00:00' was not in the correct format.

InvalidCastException: Unable to cast object of type 'System.DateTimeOffset' to type 'System.IConvertible'.

有没有人知道如何让NHibernate识别datetimeoffset列的格式而不更改映射中的sql-type?或者是否有可以在映射中使用的sql类型,它将适用于Oracle和SQL Server列类型?

1 个答案:

答案 0 :(得分:1)

DateTimeType NHibernate类型期望从datareader接收.Net DateTime,但SqlClient在读取SQL Server DateTimeOffset时确实会产生.Net DateTimeOffset。这样的SQL类型应使用DateTimeOffset NHibernate类型与.Net DateTimeOffset进行映射。

(是的,您收到的错误消息有点误导,it is emitted通过捕捉Convert.ToDateTime(rs[index]) rs DbDataReaderrs[index]的失败。在您的情况下, SQL-Server,DateTimeOffset产生string,但转换失败。消息不应该提到DateTime。)

由于这与Oracle合作,我想这意味着在阅读timestamp with time zone类型时,您的Oracle客户端会产生DateTimeOffset。这非常不幸,因为这意味着丢失了偏移量,但这也意味着Oracle不支持DbDataReader .Net类型。 (好吧,实体框架Oracle适配器似乎支持它,所以我想通过实现Oracle特定的DbDataReader实现仍然可行。但是通过使用DateTime暴露的内容是不可行的。)< / p>

所以麻烦的是Oracle和Sql-Server客户端之间关于具有时区/偏移的类型的不匹配,第一个产生.Net DateTimeOffset(顺便说一下,在您的应用程序中用于偏移的目的是什么)由于Oracle客户端不传输它?),第二个产生.Net datetime2(6)

如果像在您的示例中那样以UTC格式存储所有内容,可能应该考虑在SQL-Server端将您的列声明为简单Kind
如果您需要将其Utc正确设置为UtcDateTime来检索它,则另外将其与NHibernate类型NHibernate.UserTypes.IUserType一起映射。

否则,作为written by ewramner,您需要使用custom user type(实现DateTimeOffset的类)。他的链接是关于用Oracle处理.Net NullSafeGet的用户类型。但在您的情况下,您可能希望编写一个用DateTime方法的用户类型类,检查数据读取器产生的内容,并在需要时将其转换为{{1}}。然后在映射中使用它的程序集限定名作为属性类型。 (请参阅简单的用户类型实现here。)