2015-12-24 3 views
2

Я пытаюсь отобразить тип NodaTime OffsetDateTime на SQL Server, но я не уверен, как решить импеданс между типами OffsetDateTime и NDST SQL Server DateTimeOffset.Использование OffsetDateTime с NHibernate

Основная проблема, с которой я столкнулся, заключается в том, что LINQ поддерживает правильную работу, поскольку OffsetDateTime не имеет операторов сравнения, таких как <. Системы также отличаются тем, как они справляются с равенством. NodaTime рассматривает как мгновенное время, так и смещение, в то время как SQL Server учитывает только момент времени.

2015-12-24 11:18+01:00 и 2015-12-24 10:18+00:00 считаются равными в SQL Server, но не равны в NodaTime.

Я рассмотрел использование ICompositeUserType для хранения даты/времени UTC и смещения в отдельных столбцах (аналогично предыдущему SQL Server 2008), но OffsetDateTime не имеет свойства UTC/Instant. Поэтому я не вижу, как получить date.ToInstant() в запросах LINQ, чтобы правильно отобразить свойство в ICompositeUserType.

+0

Во-первых, Что вы пытаетесь сделать? Если вы преобразуете оба значения в моменты NodaTime, они * будут * равны - они относятся к одному и тому же моменту. Вы действительно хотите, чтобы они вели себя как разные ценности? –

+0

Во-вторых, NHibernat * отображает * ваши классы в * базу данных *. Вы не можете использовать семантику, которая не поддерживается типом базы данных. LINQ или любой ORM не меняют функциональность базы данных, они просто упрощают сопоставление между объектами и таблицами. Любое другое использование - серьезный запах –

+0

Я хочу использовать тип «OffsetDateTime» NodaTime в своих моделях и сопоставлять их с SQL Server «DateTimeOffset» или с двумя столбцами, «DateTime» сохраняет значение UTC и смещение. –

ответ

4

OffsetDateTime должен отображаться на SQL-сервере datetimeoffset. Для обеспечения этой работы будет необходима поддержка NHibernate для пользовательских сопоставлений типов через IUserTypeas described in this article.

Хотя OffsetDateTime не осуществляет непосредственно IComparable, вы можете использовать OffsetDateTime.Comparer.Instant, чтобы сравнить их. Это может быть сложно использовать в запросах LINQ, но это один из путей для изучения.

Возможно, кто-то должен написать пакет интеграции NHibernate-NodaTime, чтобы сделать это проще. Учитывая, что я сделал это раньше для RavenDB и для Dapper, я рассмотрю его. :)

Извините, у меня нет лучшего фактического ответа «сделайте это» для вас.


UPDATE

Я начал работать над этим, и успешно построил IUserType для OffsetDateTime, но это не работает для операторов сравнения - по той причине, которую вы описали. Я считаю, что решение включает в себя расширение провайдера 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-провайдере.


ВТОРАЯ UPDATE

Кто-то бил меня к нему. В настоящее время существует набор расширений для NHibernate для поддержки типов данных Noda Time in this project. :)

+0

@JonSkeet (если вы это читаете) обратите внимание на то, как не иметь сопоставления по умолчанию для 'OffsetDateTime' вызывает проблемы в таких контекстах, как этот. Кроме того, обратите внимание, что сравнение с * локальным временем * было бы невозможно реализовать здесь, потому что в конечном итоге LINQ будет переведен в оператор SQL, а SQL * всегда * сравнивает типы datetimeoffset по их эквиваленту UTC. –

+0

Yup, я читаю :) Так вы думаете, что 'OffsetDateTime' должно иметь сравнение по умолчанию, которое происходит по времени, например SQL? Обратите внимание, что это не будет совместимо с равенством, которое будет сравнивать смещение, а также мгновенное ... что делает SQL? –

+0

Я получил рабочую реализацию этой концепции https://gist.github.com/chilversc/d1ba1fdbae58d8a13704 с помощью пользовательского «LinqToHqlGeneratorsRegistry» и обработки метода «ToInstant». В моей реализации я использовал составной тип пользователя как его устаревшую БД, которая имеет отдельные столбцы даты/времени UTC и офсетные столбцы. –