Using MultiCriteria
使用多条件(MultiCriteria)
为了显示大量的表单和web页面,我们需要运行好几个查询. 例如,将查询结果一次显示在一个页面里是很正常的,这通常需要两个查询.第一个统计所有有效的结果,第二个,只获取10个/20个结果的数据.MultiCriteria使得我们可以将这两个查询整合到一次数据库交互,以提高应用程序的性能.本节介绍如何使用MultiCriteria去获取products的一个分页的结果集.
准备
1. 完成本章简介中的通用步骤.
2. 在Queries类中,添加下面的结构:


public struct PageOf<T> { public int PageCount; public int PageNumber; public IEnumerable<T> PageOfResults; }
3. 在Queries类中,添加下面的方法:


public PageOf<Product> GetPageOfProducts( int pageNumber, int pageSize) { var skip = (pageNumber - 1) * pageSize; var countQuery = GetCountQuery(); var resultQuery = GetPageQuery(skip, pageSize); var multiCrit = _session.CreateMultiCriteria() .Add<int>("count", countQuery) .Add<Product>("page", resultQuery); var productCount = ((IList<int>)multiCrit .GetResult("count")).Single(); var products = (IList<Product>)multiCrit .GetResult("page"); var pageCount = (int) Math.Ceiling( productCount/(double) pageSize); return new PageOf<Product>() { PageCount = pageCount, PageOfResults = products, PageNumber = pageNumber }; } private ICriteria GetCountQuery() { return _session.QueryOver<Product>() .Select(list => list .SelectCount(m => m.Id)) .UnderlyingCriteria; } private ICriteria GetPageQuery(int skip, int take) { return _session.QueryOver<Product>() .OrderBy(m => m.UnitPrice).Asc .Skip(skip) .Take(take) .UnderlyingCriteria; }
4. 在Program.cs中, 为RunQueries方法添加下述代码:


static void RunQueries(ISession session) { var queries = new Queries(session); var result = queries.GetPageOfProducts(1, 2); var heading = string.Format("Page {0} of {1}", result.PageNumber, result.PageCount); Show(heading, result.PageOfResults); }
5. 编译运行,结果如下图所示:
原理
MultiCriteria API在所有NHibernate支持的RDBMS上都可以使用.但是,只有在Microsoft SQL Server和Oracle可以将两个查询整合到一次数据库交互中.而对于其他的数据库,该功能是模拟实现的.你的应用程序不必关注这个,总之,可以正常使用她.
在本示例中,我们将两个查询整合到一次数据库交互中.我们的第一个查询,统计了数据库中所有的products,第二个查询,返回了一个页面,该页面含有三个products中的前两个,并按单价排序.我们使用QueryOver的Skip和Take实现该功能.
在MultiCriteria语法中,有几个挺有意思的东西.
var multiCrit = session.CreateMultiCriteria()
.Add<int>("count", countQuery)
.Add<Movie>("page", resultQuery);
首先, 你会注意到我们使用"count"和"page"标记了我们的查询.这不是必须的.相反,我们可以使用MultiCriteria中每个criteria对象的索引来获取结果.与列表索引相比,名字更不容易被搞乱,所以我们将使用名字.
我们使用泛型参数来为我们的结果指明元素类型.也就是说,我们的第一个查询返回一个整数list,第二个返回一个movies的list.MultiCriteria没有提供一个方法来直接返回一个单一的实体或标量值.相反,我们使用LINQ to Object's的Single方法来获取list中的第一个也是唯一的一个值.
当我们获得了product的计数时,两个查询都会被立即执行,并且结果被存储到内存中.当我们获得product的页面时,MultiCriteria 只返回已执行的查询的结果.