2009-05-08 8 views
0

私は、主キーとソート順を与えられたNHibernateクエリの "周囲の"行を取得する方法を探していますか?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 

は、我々は1237年、1238年と4239 4247.順に行を取得する必要があり、主キー4242を持つエントリを請求する場合:

編集追加されたサンプル

は、次のようなデータを想像してみてTime、Idです。

(明らかにサブクエリを含むことができる)単一のクエリのエントリを取得することは可能ですか?時間はユニークではない列なので、いくつかの項目が同じ値を持ち、この例では、ユニークな方法で解像度を変更することはできません!

答えて

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); 
+0

宣伝通りに動作します。異なる列で並べ替える必要があるので、シーケンス列を維持することはできません。 私は非固有の列を並べ替える必要がある状況では、より多くのアイデアが歓迎されるよりも多くの状況のた​​めにrownumソリューションを探していました:-) – HakonB

+0

新しいセクションを参照してください。 –

0

これは、NHibernateののクライテリアAPIで比較的簡単にする必要があります。ここでは

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

listOfIdsはあなたが取得したいエントリのIDを表す整数(整数4242から5の強く型付けされたリストはちょうどです4242 + 5まで)。

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

+1

どのように私は評判を得るつもりですか? :)私が5分以内に回答を掲示したときに、他の誰かが1つも投稿しました。 –

+0

お金と同じです。もしあなたがそれを持っていれば、それを手に入れます。人々は評判の高いメンバーからの回答に対してより頻繁に投票します。人生は公平なものでは無い。しかし、良い答えを提供することは常に感謝し、主な意図でなければならない気にしないでください。 –

+0

Stefanが上記のように日付と主キーの間に直接の関係はないので、主キーで選択するだけでは機能しません。プライマリキーソリューションを無効にするカテゴリ別にフィルタリングする必要があるソリューションがあるかもしれません。 – HakonB

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構文ですが、同じではなく、あなたが式を使用制限の以前のバージョンのためにも当てはまります。

私はテストアプリケーションでこれをテストして、それが私はこれがある限り順序が一意の値を保持している列の上にあるように動作することを推測

+0

時間が一意である限り素晴らしいですが、PropertyGt/Ltの制限のために複数の行で「中間」時間を共有すると失敗します。しかし、PropertyGe/Leに変更するだけでは機能しません。あなたのサンプルで私の質問から時間の値を使用してみて、私が意味するものを参照してください。 Btw、あなたのコードは確かに私にサブクラスについて何か新しいことを教えてくれました:-) – HakonB

+0

bleh、一時的な失明は私に非固有の要件を逃しました。データセットには順番どおりの順序がありませんから、私は必要な答えを提供する方法が見えません – Jaguar

関連する問題