0

主キーとソート順を指定して、NHibernate クエリで「周囲の」行を取得する方法を探していますか?

たとえば、ログ エントリを含むテーブルがあり、主キー 4242 のエントリと前の 5 つのエントリ、および次の 5 つのエントリを日付順に並べて表示したい (日付と主キーの間に直接的な関係はありません)。このようなクエリは、合計で 11 行を返す必要があります (どちらかの端に近づかない限り)。

ログ エントリ テーブルは巨大になる可能性があり、すべてを取得して把握することはできません。

NHibernate 内から使用できる行番号などの概念はありますか? 基盤となるデータベースは、SQLite または Microsoft SQL Server のいずれかになります。

編集追加サンプル

次のようなデータを想像してください。

Id   Time
4237 10:00
4238 10:00
1236 10:01
1237 10:01
1238 10:02
4239 10:03
4240 10:04
4241 10:04
4242 10:04   <-- requested "center" row
4243 10:04
4244 10:05
4245 10:06
4246 10:07
4247 10:08

主キー 4242 のエントリを要求すると、行 1237、1238、および 4239 ~ 4247 を取得する必要があります。順序は時間、ID 順です。

単一のクエリ (明らかにサブクエリを含めることができます) でエントリを取得することは可能ですか? 時間は一意でない列であるため、複数のエントリが同じ値を持ちます。この例では、一意になるように解像度を変更することはできません!

4

3 に答える 3

1

「日付と主キーの間に直接的な関係はありません」とは、主キーが連続していないことを意味しますか?

次に、次のようにします。

Item middleItem = Session.Get(id);

IList<Item> previousFiveItems = Session.CreateCriteria((typeof(Item))
  .Add(Expression.Le("Time", middleItem.Time))
  .AddOrder(Order.Desc("Time"))
  .SetMaxResults(5);

IList<Item> nextFiveItems = Session.CreateCriteria((typeof(Item))
  .Add(Expression.Gt("Time", middleItem.Time))
  .AddOrder(Order.Asc("Time"))
  .SetMaxResults(5);

同時に複数のアイテムを持つリスクがあります。


編集

これで動作するはずです。

Item middleItem = Session.Get(id);

IList<Item> previousFiveItems = Session.CreateCriteria((typeof(Item))
  .Add(Expression.Le("Time", middleItem.Time)) // less or equal
  .Add(Expression.Not(Expression.IdEq(middleItem.id))) // but not the middle
  .AddOrder(Order.Desc("Time"))
  .SetMaxResults(5);

IList<Item> nextFiveItems = Session.CreateCriteria((typeof(Item))
  .Add(Expression.Gt("Time", middleItem.Time))  // greater 
  .AddOrder(Order.Asc("Time"))
  .SetMaxResults(5);
于 2009-05-08T09:10:14.600 に答える
0

ステファンのソリューションは間違いなく機能しますが、単一の選択とネストされたサブクエリを使用するより良い方法が存在します:

ICriteria crit = NHibernateSession.CreateCriteria(typeof(Item));

        DetachedCriteria dcMiddleTime =
            DetachedCriteria.For(typeof(Item)).SetProjection(Property.ForName("Time"))
            .Add(Restrictions.Eq("Id", id));

        DetachedCriteria dcAfterTime =
            DetachedCriteria.For(typeof(Item)).SetMaxResults(5).SetProjection(Property.ForName("Id"))
            .Add(Subqueries.PropertyGt("Time", dcMiddleTime));
        DetachedCriteria dcBeforeTime =
            DetachedCriteria.For(typeof(Item)).SetMaxResults(5).SetProjection(Property.ForName("Id"))
                .Add(Subqueries.PropertyLt("Time", dcMiddleTime));

        crit.AddOrder(Order.Asc("Time"));
        crit.Add(Restrictions.Eq("Id", id) || Subqueries.PropertyIn("Id", dcAfterTime) ||
                 Subqueries.PropertyIn("Id", dcBeforeTime));

        return crit.List<Item>();

これは NHibernate 2.0 の構文ですが、制限の代わりに式を使用する以前のバージョンにも同じことが当てはまります。

テストアプリケーションでこれをテストしましたが、宣伝どおりに機能します

于 2009-05-26T15:17:33.600 に答える
0

これは、NHibernate の Criteria API を使用すると比較的簡単です。

List<LogEntry> logEntries = session.CreateCriteria(typeof(LogEntry))
.Add(Expression.InG<int>(Projections.Property("Id"), listOfIds))
.AddOrder(Order.Desc("EntryDate"))
.List<LogEntry>();

ここで、 yourlistOfIdsは、取得するエントリの ID を表す厳密に型指定された整数のリストです (整数 4242-5 から 4242+5 )。

もちろんExpressions、4242-5 よりも大きく 4242+5 よりも小さい ID を取得できるように追加することもできます。

于 2009-05-08T09:11:04.427 に答える