如何将NHibernate QueryOver查询改造为异步执行?
把NHibernate QueryOver分页查询改成异步的解决方案
嘿,我之前也碰到过把QueryOver分页查询改成异步的需求,刚好可以给你捋清楚怎么弄!首先得确认你的NHibernate版本是5.0及以上——从这个版本开始,NHibernate才给QueryOver和Criteria API补上了完整的异步执行方法,这是前提哈。
其实改动没你想的那么复杂,QueryOver的查询构建逻辑(比如JoinAlias、过滤条件、投影这些)和同步写法完全一样,只是把最后的同步执行方法换成异步版本就行。针对你每次取20条的分页需求,给你整理了完整的示例:
异步分页查询代码示例
// 假设这是你的业务方法,标记为async并返回Task<T> public async Task<List<BusinessListItem>> GetPaginatedBusinessesAsync(int currentPage, CancellationToken cancellationToken = default) { BusinessListItem bli = null; BusinessCategory bc = null; Category c = null; BusinessImage bi = null; Image i = null; // 1. 构建QueryOver查询,和同步写法完全一致 var query = Session.QueryOver<Business>() .JoinAlias(x => x.Categories, () => bc) .JoinAlias(() => bc.Category, () => c) .JoinAlias(x => x.BusinessImages, () => bi) .JoinAlias(() => bi.Image, () => i) // 这里可以添加你的过滤条件,比如: // .Where(() => c.IsActive == true && x.IsVerified == true) .SelectList(list => list .Select(x => x.Id).WithAlias(() => bli.Id) .Select(x => x.Name).WithAlias(() => bli.Name) .Select(() => c.Name).WithAlias(() => bli.CategoryName) .Select(() => i.Url).WithAlias(() => bli.MainImageUrl) ) .TransformUsing(Transformers.AliasToBean<BusinessListItem>()); // 2. 分页处理:跳过前面的条目,取20条,用异步方法执行 var paginatedBusinesses = await query .Skip((currentPage - 1) * 20) // 注意页码从1开始的话要减1,从0开始就直接乘 .Take(20) .ListAsync<BusinessListItem>(cancellationToken); // 如果需要获取总条数(用于分页组件显示总页数),可以单独调用RowCountAsync var totalBusinessCount = await query.RowCountAsync(cancellationToken); return paginatedBusinesses; }
几个关键注意点
- 必须用await关键字:异步方法一定要用await去等待执行完成,别直接返回Task对象,那样会失去异步的意义,甚至导致线程阻塞。
- CancellationToken参数:加上这个参数是好习惯,允许调用方在需要的时候取消查询(比如用户关闭页面时),避免不必要的资源消耗。
- Session的线程安全:确保你的Session是按请求生命周期管理的(比如依赖注入里的PerRequest模式),NHibernate的Session本身不是线程安全的,但异步方法内部会处理好上下文切换的问题。
- 投影和转换器:如果用了
AliasToBean这类结果转换器,异步执行时要在ListAsync里指定泛型类型,确保结果正确映射到你的BusinessListItem。
内容的提问来源于stack exchange,提问作者Nanou Ponette
相关产品推荐
相关产品推荐

