Search code examples
sql-servernhibernatepagingcriteriaprojection

Adding a projection to an NHibernate criteria stops it from performing default entity selection


I'm writing an NHibernate criteria that selects data supporting paging. I'm using the COUNT(*) OVER() expression from SQL Server 2005(+) to get hold of the total number of available rows, as suggested by Ayende Rahien. I need that number to be able to calculate how many pages there are in total. The beauty of this solution is that I don't need to execute a second query to get hold of the row count.

However, I can't seem to manage to write a working criteria (Ayende only provides an HQL query).

Here's an SQL query that shows what I want and it works just fine. Note that I intentionally left out the actual paging logic to focus on the problem:

SELECT Items.*, COUNT(*) OVER() AS rowcount
FROM Items

Here's the HQL:

select
    item, rowcount()
from 
    Item item

Note that the rowcount() function is registered in a custom NHibernate dialect and resolves to COUNT(*) OVER() in SQL.

A requirement is that the query is expressed using a criteria. Unfortunately, I don't know how to get it right:

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(
       Projections.SqlFunction("rowcount", NHibernateUtil.Int32));

Whenever I add a projection, NHibernate doesn't select item (like it would without a projection), just the rowcount() while I really need both. Also, I can't seem to project item as a whole, only it's properties and I really don't want to list all of them.

I hope someone has a solution to this. Thanks anyway.


Solution

  • I think it is not possible in Criteria, it has some limits.

    You could get the id and load items in a subsequent query:

    var query = Session
        .CreateCriteria<Item>("item")
        .SetProjection(Projections.ProjectionList()
           .Add(Projections.SqlFunction("rowcount", NHibernateUtil.Int32))
           .Add(Projections.Id()));
    

    If you don't like it, use HQL, you can set the maximal number of results there too:

    IList<Item> result = Session
        .CreateQuery("select item, rowcount() from item where ..." )
        .SetMaxResult(100)
        .List<Item>();