我们有一个使用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列类型?
答案 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
DbDataReader
为rs[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。)