Лучшим (и самым разумным) способом, конечно, было бы использование NULL
значений вместо минимальных datetime
значений. Если вы сделали это (или изменили свое приложение для этого), то написанный вами код будет работать так, как написано. Теперь, я гарантирую, что эти поддельные значения в конечном итоге снова будут преследовать кого-то (если это реальное приложение). Может быть, не ты, но следующий парень. Конечно, вы должны также нормализовать эту таблицу ...
Но в любом случае. Подробнее об этом позже. Вы задали конкретный вопрос.
Вот код, который должен работать (не из-за отсутствия тестирования - продолжайте чтение).
DateTime bogusDate = new DateTime(1753, 1, 1);
ICriteria criteria =
session.CreateCriteria(typeof(Voyage))
.SetProjection
(
Projections.ProjectionList()
.Add
(
Projections.Min
(
Projections.Conditional
(
Restrictions.Eq("Departure", bogusDate),
Projections.Constant(DateTime.MaxValue, NHibernateUtil.DateTime),
Projections.Property("Departure")
)
)
)
.Add(Projections.Max("Arrival"))
.Add(Projections.GroupProperty("Id"))
);
(Единственная причина, по которой я отправляю DateTime.MaxValue
, заключается в том, что NHibernate принудительно приводит условные значения true / false к одному и тому же типу, и я не мог понять, как получить NULL
в часть true
.)
Этот код отправляет этот запрос механизму БД (я использую диалект SQL Server 2005 при поддержке SQL Express 2005):
SELECT min((case when this_.Departure = ? then ? else this_.Departure end)) as y0_,
max(this_.Arrival) as y1_,
this_.Id as y2_
FROM Voyages this_
GROUP BY this_.Id;
@p0 = 1/1/1753 12:00:00 AM,
@p1 = 12/31/9999 11:59:59 PM
Что выглядит хорошо. Теперь я говорю, что должно работать, потому что когда вы подключаете параметры и запускаете запрос непосредственно на движке, это дает желаемые результаты. Однако на моей машине, используя NHibernate, все взрывается:
System.Data.SqlClient.SqlException: Incorrect syntax near '?'.
Что говорит мне о том, что SQL Server не похож на позиционные параметры в CASE
операторах. Braindead, если это правда. Это может не быть проблемой в 2008+, хотя я не тестировал - я упоминаю SQL Server специально, потому что я предполагаю, что это то, что вы используете, поскольку 01.01.1753 - это минимальная дата, которую он позволяет datetime
.
Так, где это оставляет эту проблему? Есть варианты.
- Исправьте схему базы данных, как упомянуто в моем первом абзаце (идеально). Обратите внимание, что вам не нужно будет разрешать любые
NULL
значения в ваших данных, если схема нормализована.
- Посмотрите, можете ли вы написать запрос, используя вместо этого HQL (я не эксперт, поэтому даже не могу сказать, возможно ли это).
- Обнаружьте, что это не проблема в SQL 2008+ и / или вашей целевой системе (ах) базы данных, и это все, на что вы когда-либо собираетесь ориентироваться.
- Перепишите запрос, чтобы полностью обойти сумасшедшие значения и используйте вместо него столбец
OrderIndex
. Я написал это на SQL - я не уверен, как написать это, используя ICriteria
(и если вы хотите, чтобы за это наказали, сделайте себе одолжение и вместо этого потратьте время на вариант # 1). Обратите внимание, что это менее чем в два раза быстрее исходного запроса, что почти оптимально. AFAIK:
SELECT
s.Id,
v1.Departure,
v2.Arrival
FROM
(
SELECT DISTINCT
Id,
MAX(OrderIndex) AS MaxIndex,
MIN(OrderIndex) AS MinIndex
FROM Voyages
GROUP BY Id
) s
INNER JOIN Voyages v1 ON v1.Id = s.Id AND v1.OrderIndex = MinIndex
INNER JOIN Voyages v2 ON v2.Id = s.Id AND v2.OrderIndex = MaxIndex