2011-07-20 32 views
11

我已经阅读了某处(不能记住在哪里以及如何)NHibernate 3允许在执行分页查询(在一个数据库查询中)时确定总记录数。这是正确的吗?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(); 
} 

,并想初始化的“合计”尽可能高效。

谢谢。

基督教

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(); 

回答

23

你潜在的解决方案将在一个事务中进行处理,但将是两个数据库调用。如果您必须只有一个数据库调用,则应该使用多点查询/将来查询作为对等建议。有关未来语法的更多信息,请查看此帖: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(1级分贝的呼叫与Future):
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)] 
标准(与Future1分贝呼叫):
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)] 

请注意, e查询样式导致相同的查询。未来的语法只允许NHibernate进行一次数据库调用而不是两次。

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

+1

可能值得注意的是,两者是否导致单个查询是由方言特定的优化驱动的。例如在SQLite上发出两个查询,但行为是相同的(所有的期货尽可能少地查询) – AlexCuse

2

我不认为NHibernate的 '实现' 它执行的任何查询的意思,所以决定总数行不是标准查询。

最有效的方式来获得行计数是期货或IMultiQuery(以获得一个roundtript到数据库的结果)

nhibernate-futures

+0

我已经添加了一些内容,请参阅PS。这是你指的是什么,这个查询将在一个数据库转换?谢谢。 – cs0815

3

我没有足够的声誉以上CodeProgression的解决方案发表评论......但使用QueryOver适当ONE DB调用W /未来<>是:

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 <>查询后,执行ToList()。