NHibernate中总行数的分页

时间:2011-05-11 16:49:50

标签: nhibernate pagination hql

我正在尝试使用HQL对一个简单的查询进行分页,并检索总行数作为同一查询的一部分。

我的查询很简单......

var members = UnitOfWork.CurrentSession.CreateQuery(@"
    select m
    from ListMember as m
    join fetch m.Individual as i") 
    .SetFirstResult(pageIndex*pageSize)
    .SetMaxResults(pageSize)
    .List<ListMember>();

在ListMember类中,Individual被映射为多对一。这非常有效。分页按预期工作并生成以下Sql ...

SELECT   TOP ( 10 /* @p0 */ ) DirPeerG1_1_0_,
                 Director1_0_1_,
                 Director2_1_0_,
                 Forename2_0_1_,    
                 Surname0_1_
FROM     (SELECT listmember0_.DirPeerGrpMemberID    as DirPeerG1_1_0_,
             listmember1_.DirectorKeyID         as Director1_0_1_,
             listmember0_.DirectorKeyId         as Director2_1_0_,
             listmember1_.Forename1             as Forename2_0_1_,
             listmember1_.Surname               as Surname0_1_,
             ROW_NUMBER()
               OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row
          FROM   tblMembers listmember0_
             inner join tblIndividuals listmember1_
               on listmember0_.DirectorKeyId = listmember1_.DirectorKeyID) as query
WHERE    query.__hibernate_sort_row > 10 /* @p1 */
ORDER BY query.__hibernate_sort_row

我读过Ayende发布的这篇文章Paged data + Count(*) with NHibernate: The really easy way!,所以我试着在我的查询中实现它。

我按照文章中的步骤添加了名为rowcount()的自定义HQL函数,并将我的查询更改为此...

var members = UnitOfWork.CurrentSession.CreateQuery(@"
    select m, rowcount()
    from ListMember as m
    join fetch m.Individual as i") 
    .SetFirstResult(pageIndex*pageSize)
    .SetMaxResults(pageSize)
    .List<ListMember>();

生成的Sql几乎是正确的,但它包含两次列之一导致此错误...

  

System.Data.SqlClient.SqlException:   列'''已指定   “查询”多次。

它生成的Sql看起来像这样......

SELECT   TOP ( 10 /* @p0 */ ) 
         col_0_0_, 
         col_1_0_, 
         Director1_0_1_, 
         DirPeerG1_1_0_, 
         Director1_0_1_, 
         Director2_1_0_, 
         Forename2_0_1_,    
         Surname0_1_
FROM     (SELECT 
      listmember0_.DirPeerGrpMemberID as col_0_0_, 
      count(*) over() as col_1_0_, 
      listmember1_.DirectorKeyID as Director1_0_1_, 
      listmember0_.DirPeerGrpMemberID as DirPeerG1_1_0_, 
      listmember1_.DirectorKeyID as Director1_0_1_, 
      listmember0_.DirectorKeyId as Director2_1_0_, 
      listmember1_.Forename1 as Forename2_0_1_, 
      listmember1_.Surname as Surname0_1_, 
             ROW_NUMBER()
               OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row
          FROM   RCMUser.dbo.tblDirPeerGrpMembers listmember0_
             inner join RCMAlpha.dbo.tblDirectorProfileDetails listmember1_
               on listmember0_.DirectorKeyId = listmember1_.DirectorKeyID) as query
WHERE    query.__hibernate_sort_row > 10 /* @p1 */
ORDER BY query.__hibernate_sort_row

由于某种原因,它在投影中包含Director1_0_1_列两次,这会导致此错误。这个Sql令人沮丧地接近我想要的,我希望NHibernate专家可以帮助解释为什么会发生这种情况。

建议尝试

感谢@Jason的建议。我尝试使用非泛型版本的.List()方法执行查询,但遗憾的是,这也产生了与重复列相同的Sql ......

var members = UnitOfWork.CurrentSession.CreateQuery(@"
    select m, rowcount()
    from ListMember as m
    join fetch m.Individual as i")
    .SetFirstResult(pageIndex * pageSize)
    .SetMaxResults(pageSize)
    .List()
    .Cast<Tuple<ListMember, int>>()
    .Select(x => x.First);

更新

如果没有进入NH源代码,这似乎不可能。我的解决方案要求已经改变,我不再追求答案了。

总之,解决方案是......

  • 使用Futures或MultiQuery在一个命令中执行两个语句 - 一个用于检索数据页面,另一个用于检索总行数。
  • 修改您的分页解决方案,使其无需总计数 - 例如,连续滚动。

1 个答案:

答案 0 :(得分:1)

嗯,有一个问题是你正在使用ListMember类型的List方法。在您链接的页面的示例中,他使用List()返回元组列表。元组的第一项是ListMember,第二项是行计数。该列表&lt;&gt;可能会影响您的查询,即使它确实返回也可能抛出异常。

尝试使用:

var tuples = UnitOfWork.CurrentSession.CreateQuery(@"
select m, rowcount()
from ListMember as m
join fetch m.Individual as i") 
.SetFirstResult(pageIndex*pageSize)
.SetMaxResults(pageSize)
.List();

var members = tuples.Select<Tuple<ListMember, int>, ListMember>(x => x.Item1);

但我有点同意@dotjoe。 MultiQuery可能更容易。这就是我使用的。这是一个很好的link来自你之前链接的同一作者(Ayende)。