NHibernateでページングを行うにはどうすればよいですか?


107

たとえば、ASP.NET Webページのグリッドビューコントロールに、表示される行数に必要なデータのみを入力したいとします。NHibernateはこれをどのようにサポートできますか?

回答:


111

ICriteriaには、SetFirstResult(int i)取得する最初のアイテムのインデックスを示すメソッドがあります(基本的にはページの最初のデータ行)。

またSetMaxResults(int i)、取得する行の数(つまり、ページサイズ)を示すメソッドもあります。

たとえば、次の基準オブジェクトは、データグリッドの最初の10件の結果を取得します。

criteria.SetFirstResult(0).SetMaxResults(10);

1
これは、とにかく、Linq(to NH)構文がどのように見えるかです-ニース。
MotoWilliams 2008

13
ページャーをレンダリングするには、合計行数を取得するために別のトランザクションを実行する必要があることに注意することが重要です。
Kevin Pang

1
これにより、SQL ServerでSELECT TOPクエリが実行されます。SetFirstResult(1).SetMaxResult(2);で試してください。
クリスS

4
その前のコメントはNHibernate.Dialect.MsSql2005DialectではなくNHibernate.Dialect.MsSql2000Dialectを使用しています
Chris S

IQueryは同じ機能を備えているため、HQLでも使用できます。
goku_da_master

87

また、NHibernateのFutures機能を利用してクエリを実行し、合計レコード数と単一のクエリの実際の結果を取得することもできます。

 // Get the total row count in the database.
var rowCount = this.Session.CreateCriteria(typeof(EventLogEntry))
    .Add(Expression.Between("Timestamp", startDate, endDate))
    .SetProjection(Projections.RowCount()).FutureValue<Int32>();

// Get the actual log entries, respecting the paging.
var results = this.Session.CreateCriteria(typeof(EventLogEntry))
    .Add(Expression.Between("Timestamp", startDate, endDate))
    .SetFirstResult(pageIndex * pageSize)
    .SetMaxResults(pageSize)
    .Future<EventLogEntry>();

合計レコード数を取得するには、次のようにします。

int iRowCount = rowCount.Value;

フューチャーズがあなたに与えるものについての良い議論はここにあります


3
これは素晴らしい。Futuresは、マルチクライテリアの構文上の複雑さなしに、マルチクライテリアとまったく同じように機能します。
DavGarcia、2010年

Futuresに関する投稿を読んだ後、すべてのデータベースクエリにFutureを使用する必要があるかどうか疑問に思います...欠点は何ですか?:)
hakksor

46

NHibernate 3以降では、以下を使用できますQueryOver<T>

var pageRecords = nhSession.QueryOver<TEntity>()
            .Skip((PageNumber - 1) * PageSize)
            .Take(PageSize)
            .List();

次のように結果を明示的に並べることもできます。

var pageRecords = nhSession.QueryOver<TEntity>()
            .OrderBy(t => t.AnOrderFieldLikeDate).Desc
            .Skip((PageNumber - 1) * PageSize)
            .Take(PageSize)
            .List();

.Skip(PageNumber * PageSize)この方法では、ページサイズが10の場合、最初の10行は取得されません。数式を正しくするために編集しています。概念的に、と仮定するとPageNumber0にすべきではないことはそれが1、最低でなければなりません
アミット・ジョシ

31
public IList<Customer> GetPagedData(int page, int pageSize, out long count)
        {
            try
            {
                var all = new List<Customer>();

                ISession s = NHibernateHttpModule.CurrentSession;
                IList results = s.CreateMultiCriteria()
                                    .Add(s.CreateCriteria(typeof(Customer)).SetFirstResult(page * pageSize).SetMaxResults(pageSize))
                                    .Add(s.CreateCriteria(typeof(Customer)).SetProjection(Projections.RowCountInt64()))
                                    .List();

                foreach (var o in (IList)results[0])
                    all.Add((Customer)o);

                count = (long)((IList)results[1])[0];
                return all;
            }
            catch (Exception ex) { throw new Exception("GetPagedData Customer da hata", ex); }
      }

データのページングがMultiCriteriaから型付けされた結果を取得する別の方法がある場合、または誰もが私のように同じことをしますか?

ありがとう


23

Ayendeによるこのブログ投稿で説明されているように、Linq to NHibernateを使用するのはどうですか?

コードサンプル:

(from c in nwnd.Customers select c.CustomerID)
        .Skip(10).Take(10).ToList(); 

また、ページングの実装を含む、NHibernate使用したデータアクセスに関するNHibernateチームのブログによる詳細な投稿を次に示します。


Nhibernateへのlinqはcontribパッケージに含まれており、NHibernate 2.0リリースには含まれていません
Richard

11

ほとんどの場合、GridViewでは、データのスライスと、クエリに一致したデータの総量の行の総数(rowcount)を表示する必要があります。

選択カウント(*)クエリと.SetFirstResult(n).SetMaxResult(m)クエリの両方を1回の呼び出しでデータベースに送信するには、マルチクエリを使用する必要があります。

結果は、データスライス用とカウント用の2つのリストを含むリストになります。

例:

IMultiQuery multiQuery = s.CreateMultiQuery()
    .Add(s.CreateQuery("from Item i where i.Id > ?")
            .SetInt32(0, 50).SetFirstResult(10))
    .Add(s.CreateQuery("select count(*) from Item i where i.Id > ?")
            .SetInt32(0, 50));
IList results = multiQuery.List();
IList items = (IList)results[0];
long count = (long)((IList)results[1])[0];

6

ページネーションに対処するための特定の構造を作成することをお勧めします。次のようなものです(私はJavaプログラマですが、簡単にマッピングできるはずです)。

public class Page {

   private List results;
   private int pageSize;
   private int page;

   public Page(Query query, int page, int pageSize) {

       this.page = page;
       this.pageSize = pageSize;
       results = query.setFirstResult(page * pageSize)
           .setMaxResults(pageSize+1)
           .list();

   }

   public List getNextPage()

   public List getPreviousPage()

   public int getPageCount()

   public int getCurrentPage()

   public void setPageSize()

}

私は実装を提供しませんでしたが、@Jonによって提案されたメソッドを使用できます。ここでは、あなたが見てみるのに良い議論があります。


0

2つの基準を定義する必要はありません。1つを定義してそれを複製できます。nHibernate基準を複製するには、簡単なコードを使用できます。

var criteria = ... (your criteria initializations)...;
var countCrit = (ICriteria)criteria.Clone();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.