Проблема формата даты NHibernate для преобразованной базы данных - PullRequest
0 голосов
/ 25 мая 2018

У нас есть приложение, использующее NHibernate для подключения к базе данных Oracle.Мне было поручено преобразовать базу данных Oracle в базу данных SQL Server таким образом, чтобы переключаться между базами данных так же просто, как менять драйверы NHibernate.В моей базе данных Oracle у меня есть столбец, определенный как 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-типа в отображении?Или есть тип sql, который я могу использовать в сопоставлении, который будет работать как для типов столбцов Oracle, так и для SQL Server?

1 Ответ

0 голосов
/ 29 мая 2018

Тип DateTimeType NHibernate ожидает получения .Net DateTime от устройства чтения данных, но SqlClient действительно выдает .Net DateTimeOffset при чтении SQL Server DateTimeOffset.Такой тип SQL должен быть сопоставлен с .Net DateTimeOffset с использованием DateTimeOffset типа NHibernate.

(Да, полученное вами сообщение об ошибке немного вводит в заблуждение, оно испускается перехватив ошибку Convert.ToDateTime(rs[index]), где rs - это DbDataReader. В вашем случае, с SQL-сервером, rs[index] возвращает DateTimeOffset, который завершается неудачно преобразованием. В сообщении не должно упоминаться string.)

Поскольку это работало с Oracle, я думаю, это означает, что ваш клиент Oracle выдает DateTime при чтении типа timestamp with time zone.Это весьма прискорбно, поскольку это означает потерю смещения, но также это означает, что тип DateTimeOffset .Net не может поддерживаться Oracle.(Что ж, адаптер Entity Framework Oracle, кажется, поддерживает его, так что я думаю, что это все еще выполнимо, достигнув специфической реализации DbDataReader для Oracle. Но это невозможно сделать, используя только то, что предоставляет DbDataReader.)

Таким образом, проблема заключается в том, что несоответствие между клиентами Oracle и Sql-Server относительно типов с часовым поясом / смещением, первое из которых приводит к .Net DateTime (кстати, какая цель служит смещению в вашем приложении, поскольку клиент Oracleне передает его?), второе дает .Net DateTimeOffset.

Если, как и в вашем примере, вы храните все в UTC, возможно, стоит подумать об объявлении вашего столбца простым datetime2(6) наСторона SQL-сервера.
Если вам нужно получить его с Kind, правильно установленным как Utc, то дополнительно сопоставьте его с типом NHibernate UtcDateTime.

В противном случае, как написано по ewramner вам необходимо использовать пользовательский тип пользователя (класс, реализующий NHibernate.UserTypes.IUserType).Его ссылка о типе пользователя для обработки .Net DateTimeOffset с Oracle.Но в вашем случае вы захотите вместо этого написать класс пользовательского типа с методом NullSafeGet, проверяющим, что дает считыватель данных, и конвертирующим его в DateTime при необходимости.Затем в своем отображении используйте его, указав его квалифицированное имя сборки в качестве типа свойства.(См. Простую реализацию пользовательского типа здесь .)

...