もちろん、最善の (そして最も健全な) 方法は、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"))
);
(私が a を送信する唯一の理由DateTime.MaxValue
は、NHibernate が条件付きの true/false の結果を同じ型に強制するためであり、NULL
そのtrue
部分に a を取得する方法がわかりませんでした。)
そのコードは、このクエリを DB エンジンに送信します (私は、SQL Express 2005 に支えられた SQL Server 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
。本当ならブレインデッド。これは 2008 年以降の問題ではないかもしれませんが、私はテストしていません。特に SQL Server について言及しているのは、1753 年 1 月 1 日が許容される最小の日付であるため、SQL Server を使用していると想定しているためです。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