NHibernate中C#调用SetFirstResult()查询第一页时崩溃
问题分析与解决
首先明确:*(page-1)sizeToShowOnOnePage的分页计算是正确的,第一页page=1时起始位置为0,这不是导致执行失败的原因。
你遇到的问题根源在于NHibernate对原生SQL分页的处理逻辑:当你的查询外层包含SELECT *和窗口函数COUNT(*) OVER()时,NHibernate自动添加Top(?)的方式会破坏原有查询结构,导致语法错误。
具体解决方法
1. 替换SELECT *为明确字段列表
避免使用SELECT *,手动列出所有需要返回的字段(包括子查询中的字段和TotalCount)。NHibernate对明确字段的解析更稳定,能正确生成符合语法的分页SQL:
string queryString = @" SELECT subquery.Field1, subquery.Field2, -- 列出所有子查询中的字段 COUNT(*) OVER() AS TotalCount FROM (" + sb.ToString() + @") AS subquery ORDER BY PlanTranDate";
2. 手动编写分页SQL(推荐)
如果必须保留原生SQL结构,直接在SQL中手动实现分页逻辑,跳过NHibernate的SetFirstResult和SetMaxResults,避免其自动修改SQL:
int offset = (page - 1) * sizeToShowOnOnePage; string queryString = $@" SELECT * FROM ( SELECT *, COUNT(*) OVER() AS TotalCount FROM ({sb.ToString()}) AS subquery ORDER BY PlanTranDate ) AS paged_data OFFSET {offset} ROWS FETCH NEXT {sizeToShowOnOnePage} ROWS ONLY";
(注:此语法适用于SQL Server 2012+,如果是其他数据库,需替换为对应分页语法,比如MySQL用LIMIT offset, size)
3. 改用NHibernate查询API
放弃原生SQL,使用NHibernate的QueryOver或Criteria API构建查询,让NHibernate自动处理分页和结果映射,能从根源避免这类原生SQL的兼容问题:
var query = session.QueryOver<YourEntity>() .SelectList(list => list .Select(x => x.Field1) .Select(x => x.Field2) // 添加所有需要的字段 .SelectProjections(Projections.RowCountInt64().WithAlias(() => abcListVo.TotalCount)) ) .OrderBy(x => x.PlanTranDate).Asc .TransformUsing(Transformers.AliasToBean<abcListVo>()) .Skip((page - 1) * sizeToShowOnOnePage) .Take(sizeToShowOnOnePage); rvalue = query.List<abcListVo>();
内容的提问来源于stack exchange,提问作者Sana
相关产品推荐
相关产品推荐

