For example, I want to populate a gridview control in an ASP.NET web page with only the data necessary for the # of rows displayed. How can NHibernate support this?
8 Answers
ICriteria
has a SetFirstResult(int i)
method, which indicates the index of the first item that you wish to get (basically the first data row in your page).
It also has a SetMaxResults(int i)
method, which indicates the number of rows you wish to get (i.e., your page size).
For example, this criteria object gets the first 10 results of your data grid:
criteria.SetFirstResult(0).SetMaxResults(10);

- 5,527
- 2
- 32
- 48

- 94,284
- 15
- 101
- 152
-
1This is pretty much what the Linq (to NH) syntax would look like anyway - Nice. – MotoWilliams Sep 17 '08 at 05:04
-
13It's important to note that you will need to execute a separate transaction for retrieving the total row count in order to render your pager. – Kevin Pang Jan 07 '09 at 00:44
-
1This performs a SELECT TOP query in SQL Server. Try it with SetFirstResult(1).SetMaxResult(2); – Chris S Feb 08 '09 at 17:02
-
4That's previous comment is using NHibernate.Dialect.MsSql2000Dialect not NHibernate.Dialect.MsSql2005Dialect – Chris S Feb 08 '09 at 17:20
-
IQuery has the same functions, so it can be used with HQL as well. – goku_da_master Nov 12 '12 at 17:26
You can also take advantage of the Futures feature in NHibernate to execute the query to get the total record count as well as the actual results in a single query.
Example
// 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>();
To get the total record count, you do the following:
int iRowCount = rowCount.Value;
A good discussion of what Futures give you is here.

- 1,265
- 9
- 5
-
3This is great. Futures works exactly like multicriteria without the syntactical complexity of multicriteria. – DavGarcia May 30 '10 at 17:11
-
After reading the post about Futures I'm left wondering if I should use Future for all my database queries... What's the drawback? :) – hakksor Mar 29 '11 at 10:16
From NHibernate 3 and above, you can use QueryOver<T>
:
var pageRecords = nhSession.QueryOver<TEntity>()
.Skip((PageNumber - 1) * PageSize)
.Take(PageSize)
.List();
You may also want to explicitly order your results like this:
var pageRecords = nhSession.QueryOver<TEntity>()
.OrderBy(t => t.AnOrderFieldLikeDate).Desc
.Skip((PageNumber - 1) * PageSize)
.Take(PageSize)
.List();

- 15,448
- 21
- 77
- 141

- 471
- 4
- 2
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); }
}
When paging data is there another way to get typed result from MultiCriteria or everyone does the same just like me ?
Thanks

- 6,405
- 8
- 47
- 61
How about using Linq to NHibernate as discussed in this blog post by Ayende?
Code Sample:
(from c in nwnd.Customers select c.CustomerID)
.Skip(10).Take(10).ToList();
And here is a detailed post by the NHibernate team blog on Data Access With NHibernate including implementing paging.

- 29,209
- 17
- 56
- 74
-
Note linq to Nhibernate is in the contrib package and not included in NHibernate 2.0 release – Richard Sep 23 '08 at 08:54
Most likely in a GridView you will want to show a slice of data plus the total number of rows (rowcount) of the total amount of data that matched your query.
You should use a MultiQuery to send both the Select count(*) query and .SetFirstResult(n).SetMaxResult(m) queries to your database in a single call.
Note the result will be a list that holds 2 lists, one for the data slice and one for the count.
Example:
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];

- 2,416
- 2
- 23
- 32
I suggest that you create a specific structure to deal with pagination. Something like (I'm a Java programmer, but that should be easy to map):
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()
}
I didn't supply an implementation, but you could use the methods suggested by @Jon. Here's a good discussion for you to take a look.

- 1
- 1

- 14,231
- 6
- 39
- 42
You don't need to define 2 criterias, you can define one and clone it. To clone nHibernate criteria you can use a simple code:
var criteria = ... (your criteria initializations)...;
var countCrit = (ICriteria)criteria.Clone();

- 479
- 6
- 11