NHibernate中总行数的分页

And*_*age 5 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>();
Run Code Online (Sandbox Code Playgroud)

Individual在ListMember类中映射为多对一.这非常有效.分页按预期工作并生成以下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
Run Code Online (Sandbox Code Playgroud)

我读过Ayende发布的这篇文章,称为Paged data + Count(*)和NHibernate:真的很简单!,所以我试着在我的查询中实现它.

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

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>();
Run Code Online (Sandbox Code Playgroud)

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

System.Data.SqlClient.SqlException:为'query'多次指定了列'...'.

它生成的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
Run Code Online (Sandbox Code Playgroud)

由于某种原因,它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);
Run Code Online (Sandbox Code Playgroud)

更新

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

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

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

Jas*_*tas 1

嗯,一个问题是您正在使用 ListMember 类型的 List 方法。在您链接的页面的示例中,他使用 List() 返回元组列表。元组的第一项是 ListMember,第二项是行数。该 List<> 可能会影响您的查询,并且即使它确实返回也可能会引发异常。

尝试使用:

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);
Run Code Online (Sandbox Code Playgroud)

但我有点同意@dotjoe。MultiQuery 可能更容易。这就是我用的。这是一个关于它的很好的链接,来自您之前链接到的同一位作者(Ayende)。