bugfix> sql-server > 投稿

NHibernateを使用してOracleデータベースに接続するアプリがあります。私は、DB間の切り替えがNHibernateドライバーの変更と同じくらい簡単になるように、Oracle DBをSQL Server DBに変換することを任されてきました。私の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。ただし、このテーブルを照会しようとすると、次の2つの例外が発生します。

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'.

マッピングのsql-typeを変更せずにNHibernateにdatetimeoffset列の形式を認識させる方法を知っている人はいますか?または、OracleとSQL Serverの両方の列タイプで機能するマッピングで使用できるsqlタイプがありますか?

回答 1 件
  • ザ・ DateTimeType  NHibernateタイプは、.Net DateTime の受信を期待しています  データリーダーからですが、SqlClientは.Net DateTimeOffset を生成します  SQL Server DateTimeOffset を読み取るとき 。このようなSQLタイプは、.Net DateTimeOffset を使用してマップする必要があります 、 DateTimeOffset を使用して  NHibernateタイプ。

    (はい、受け取ったエラーメッセージは誤解を招く可能性があり、 Convert.ToDateTime(rs[index]) の失敗をキャッチすることで出力されます  ここで、 rs  は DbDataReader です 。あなたの場合、SQL-Serverで rs[index]   DateTimeOffset を生成します  変換に失敗します。メッセージにはw​​yzwyzを記載しないでください  確かに。)

    これはOracleで動作していたため、Oracleクライアントが string を生成することを意味すると思います   DateTime を読むとき  タイプ。これはオフセットを失うことを意味するため非常に残念ですが、これは timestamp with time zone も意味します  .NetタイプはOracleではサポートされません。 (まあ、Entity Framework Oracleアダプターはそれをサポートしているようですので、Oracle固有の DateTimeOffset に到達することでまだ実行可能であると思います  実装。しかし、それはまさに DbDataReader を使用して実行できません  露出します。)

    したがって、問題は、タイムゾーン/オフセットを持つ型に関するOracleクライアントとSql-Serverクライアント間の不一致であり、最初に.Net DbDataReader が生成されます  (ところで、Oracleクライアントはオフセットを送信しないため、アプリケーションでオフセットを提供する目的は何ですか?)、2番目は.Net DateTime を生成します 。

    あなたの例のように、すべてをUTCで保存する場合、列を単純な DateTimeOffset として宣言することを検討する必要があります  SQLサーバー側。
    datetime2(6) で取得する必要がある場合   Kind として正しく設定 、さらにNHibernateタイプ Utc でマッピングします 。

    それ以外の場合、ewramnerによって書かれたように、カスタムユーザータイプ( UtcDateTime を実装するクラス)を使用する必要があります )。彼のリンクは、.Net NHibernate.UserTypes.IUserType を処理するためのユーザータイプに関するものです。  Oracleで。しかし、あなたの場合は、代わりに DateTimeOffset を使用してユーザータイプクラスを記述したいでしょう。  データリーダーの実行内容を確認し、それを NullSafeGet に変換するメソッド  必要に応じて。次に、マッピングで、アセンブリの修飾名をプロパティタイプとして指定して使用します。 (ここで簡単なユーザータイプの実装を参照してください。)

    DateTime

あなたの答え