【发布时间】:2011-08-23 11:51:04
【问题描述】:
我正在尝试使用 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>();
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
我阅读了 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 在单个命令中执行两条语句 - 一条用于检索数据页,一条用于获取总行数。
- 修改您的分页解决方案以不计算结果总数 - 例如连续滚动。
【问题讨论】:
-
如何访问 ListMembers 列表中的 rowcount 字段?一起使用期货和批处理 2 查询(行数和页数)可能更容易。
-
非常感谢@dotjoe。在尝试使用这种技术之前,它确实以有记录的方式使用期货工作,并且我得到了我想要的行为。我不喜欢的是两个查询必须具有相同的 FROM、JOIN 和 WHERE 部分才能使用相同的数据集,而且我的印象(可能是错误的)这会使一些工作加倍因此可以提高性能。我很想知道情况是否如此。也许 SqlServer 缓存了部分第一页查询,以便在批处理时用于计数查询?
-
@dotjoe。至于您关于如何检索行数的问题。我必须承认我没有考虑到它需要的那么多想法,但我希望使用自定义 ResultTransformer 以某种方式将对象元组与行计数元组分开。我什至不确定这是否可行:-(
-
哦,至于为未来的 2 个查询重复您的努力。您可以在设置分页/投影位之前使用
ToRowCountQuery()方法。这将克隆查询,因此您将拥有相同的 where 子句。 -
我最近遇到了
ToRowCountQuery(),它肯定可以让我重用查询。但我更关心的是数据库服务器必须做的额外工作来执行一批两个查询,而不是一个也返回总行数的单个查询。
标签: nhibernate pagination hql