NHibernate 3分页并确定总行数

时间:2011-07-20 11:32:56

标签: nhibernate

我已经阅读了NHibernate 3允许在执行分页查询(在一个数据库查询中)时确定记录总数的某处(无法记住何处和如何)。这是对的吗?

我有这段代码:

public IEnumerable<X> GetOrganisms(int PageSize, int Page, out int total)
{
    var query = (from e in Session.Query<X>() select e).AsQueryable();

    return query.Skip((Page - 1) * PageSize).Take(PageSize).ToList();
}

并希望尽可能高效地初始化'total'。

感谢。

基督教

PS:

潜在的“解决方案”?:

Total = (int) Session.CreateCriteria<X>()
.SetProjection(Projections.RowCount())
.FutureValue<Int32>().Value;

var query = (from e in Session.Query<X>() select e).AsQueryable();

return query.Skip((Page - 1) * PageSize).Take(PageSize).ToList();

3 个答案:

答案 0 :(得分:24)

您的潜在解决方案将在一个事务中处理,但将是两个db调用。如果您必须只有一个数据库调用,则应使用同步建议的多查询/未来查询。有关将来语法的更多信息,请查看以下帖子:http://ayende.com/blog/3979/nhibernate-futures

以下是完成您的方案的几种方法......

QueryOver(2分贝调用):
var query = session.QueryOver<Organism>();
var result = query
    .Skip((Page - 1) * PageSize)
    .Take(PageSize)
    .List();
var rowcount = query.RowCount();

使用100个生物体的样本集,并查询生物体11-20,以下是发送到数据库的两个查询:

SELECT TOP (@p0) Id0_0_, Title0_0_ FROM (SELECT this_.Id as Id0_0_, this_.Title as Title0_0_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM Organism this_) as query WHERE query.__hibernate_sort_row > @p1 ORDER BY query.__hibernate_sort_row;@p0 = 10 [Type: Int32 (0)], @p1 = 10 [Type: Int32 (0)]
SELECT count(*) as y0_ FROM Organism this_
QueryOver(使用Future进行1分贝调用):
var query = session.QueryOver<Organism>()
    .Skip((Page - 1) * PageSize)
    .Take(PageSize)
    .Future<Organism>();
var result = query.ToList();
var rowcount = session.QueryOver<Organism>()
    .Select(Projections.Count(Projections.Id()))
    .FutureValue<int>().Value;

查询与以前相同的数据集,这是生成的查询:

SELECT TOP (@p0) Id0_0_, Title0_0_ FROM (SELECT this_.Id as Id0_0_, this_.Title as Title0_0_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM Organism this_) as query WHERE query.__hibernate_sort_row > @p1 ORDER BY query.__hibernate_sort_row;SELECT count(this_.Id) as y0_ FROM Organism this_;;@p0 = 10 [Type: Int32 (0)], @p1 = 10 [Type: Int32 (0)]
标准(使用Future进行1分贝调用):
var criteria = session.CreateCriteria<Organism>()
    .SetFirstResult((Page - 1) * PageSize)
    .SetMaxResults(PageSize)
    .Future<Organism>();
var countCriteria = session.CreateCriteria<Organism>()
    .SetProjection(Projections.Count(Projections.Id()))
    .FutureValue<int>().Value;

再次,查询同一组数据,在同一查询中使用未来结果的标准:

SELECT TOP (@p0) Id0_0_, Title0_0_ FROM (SELECT this_.Id as Id0_0_, this_.Title as Title0_0_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM Organism this_) as query WHERE query.__hibernate_sort_row > @p1 ORDER BY query.__hibernate_sort_row;SELECT count(this_.Id) as y0_ FROM Organism this_;;@p0 = 10 [Type: Int32 (0)], @p1 = 10 [Type: Int32 (0)]

请注意,所有三种查询样式都会产生完全相同的查询。未来的语法只允许NHibernate进行一次数据库调用,而不是两次。

如果您使用的是NHibernate 3,我认为最优雅的方法是使用新的QueryOver语法。 (您在建议的解决方案中使用了旧的NHibernate.Linq语法。您最好学习QueryOver语法。)

答案 1 :(得分:3)

我没有足够的声誉来评论CodeProgression上面的解决方案......但使用QueryOver进行正确的ONE DB调用w / Future&lt;&gt;是:

var query = session.QueryOver<Organism>()
    .Skip((Page - 1) * PageSize)
    .Take(PageSize)
    .Future<Organism>();
// var result = query.ToList();
var rowcount = session.QueryOver<Organism>()
    .Select(Projections.Count(Projections.Id()))
    .FutureValue<int>().Value;
var result = query.ToList();
int iRowCount = rowcount.Value();

执行.ToList()后 - 它将命中数据库。因此,您必须再次访问数据库以获取rowCount ...这违背了Future&lt;&gt;的目的。完成所有你的.Future&lt;&gt;之后你的ToList()查询。

答案 2 :(得分:2)

我不认为nhibernate'意识到'它执行的任何查询的含义,因此确定不是标准查询的总行数。

获取行数的最有效方法是使用期货或IMultiQuery(将所有结果一次性转移到数据库中)

nhibernate-futures