摘要

上一篇文章介绍了NHibernate HQL,他的缺点是不能够在编译时发现问题。如果数据库表结构有改动引起了实体关系映射的类有改动,要同时修改这些HQL字符串。这篇文章介绍NHibernate面向对象的Criteria查询。他提供了很多API接口,可以实现“私人订制”式的面向对象查询。

作为对照,本篇文章将上篇文章的八个HQL查询全部用Criteria查询写一遍,读者可以自己感受下他们之间的区别。

本篇文章的代码可以到NHibernate查询下载

1、创建Criteria对象,查询所有Customer对象信息

         public IList<Customer> QueryAllCriteria()
{
return Session.CreateCriteria<Customer>().List<Customer>();
}

ISession.CreateCriteria方法返回持久化查询对象的ICriteria实例,他是使用Criteria查询的第一步。传入一个类型参数,表示是对哪一个实体类持久化对象的查询实例。List方法返回持久化类的所有对象。

2、CreateAlias方法创建别名

         public IList<Customer> QueryAllCriteria()
{
return Session.CreateCriteria<Customer>()
.CreateAlias("Customer", "c").List<Customer>();
}

3、指定对象返回数组

         public IList<int> SelectIdCriteria()
{
IList<int> ids = Session.CreateCriteria(typeof(Customer))
.SetProjection(Projections.Distinct(Projections.ProjectionList().Add(Projections.Property("Id"))))
.List<int>();
return ids;
}

ICriteria.SetProjection方法将应用投影到查询中,Projections有很多静态方法生成Distinct、GroupBy、Max、Min、Avg、Sum等投影。

4、添加查询条件

         public IList<Customer> GetCustomerByNameCriteria(string firstName, string lastName)
{
return Session.CreateCriteria<Customer>()
.Add(Restrictions.And(
Restrictions.Eq("FirstName", firstName), Restrictions.Eq("LastName", lastName))
).List<Customer>();
} public IList<Customer> GetCustomersStartWithCriteria()
{
var list = Session.CreateCriteria<Customer>().Add(Restrictions.Like("FirstName", "J%")).List<Customer>();
return list.ToList();
}

ICriteria.Add方法用来添加where条件,Restrictions类提供了很多生成查询条件的API方法。

Restrictions.And方法和Restrictions.Or方法对应SQL的and和or条件,可以传入多个条件对象拼接and/or子句,可以灵活地使用括号进行分组。

示例中的Restrictions.Eq方法和Restrictions.Like方法是最常用的Restrictions方法API。

此外,Restrictions还提供Between、Ge、Gt、Le、Lt、In、IsNotNull、IsNull、Where等多个API方法,可以满足生成大部分查询条件。

5、order by

         public IList<Customer> GetCustomersOrderByCriteria()
{
var list = Session.CreateCriteria<Customer>().AddOrder(new NHibernate.Criterion.Order("FirstName", true)).List<Customer>();
return list.ToList();
}

ICriteria.AddOrder方法添加order子句,传入Criteria.Order对象。Criteria.Order类构造函数传入两个参数,第一个参数表示对哪个属性进行排序,第二个字段表示是升序还是降序,true是升序,false是降序。

6、关联查询

1)按分组查询客户Id及客户关联的订单数量

         public IList<object[]> SelectOrderCountCriteria()
{
var query = Session.CreateCriteria(typeof(Customer)).CreateCriteria("Orders")
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("Id"))
.Add(Projections.RowCount()));
return query.List<object[]>();
}

对查询进行分组通用的代码是:

            var query = Session.CreateCriteria(typeof(类名))
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("属性名"))
.Add(Projections.RowCount() | Projections.Max("Max投影属性名") | Projections.Sum("Sum投影属性名")));

因为要对Order记录进行分组统计,所以使用CreateCriteria("Orders")创建与Orders的关联。

2)查询在指定日期到当前内所有下订单客户信息

         public IList<Customer> GetCustomersOrderDateGreatThanCriteria(DateTime orderDate)
{
return Session.CreateCriteria<Customer>().CreateCriteria("Orders").Add(Restrictions.Gt("Ordered", orderDate))
.SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())
.List<Customer>();
}

ICriteria.SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())的结果相当于对HQL查询使用了distinct子句。

3)查询所有订单数量大于2的客户信息

         public IList<Customer> GetCustomersOrderCountGreaterThanCriteria()
{
var query = Session.CreateCriteria(typeof(Customer)).CreateCriteria("Orders")
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("Id"))
.Add(Projections.RowCount()));
IList<object[]> groups = query.List<object[]>(); IList<int> ids = groups.Where(g => (int)g[] > ).Select(g => (int)g[]).ToList(); return Session.CreateCriteria(typeof(Customer))
.Add(Restrictions.In("Id", ids.ToArray<int>()))
.List<Customer>();
}

因为ICriteria目前不支持对Group分组结果进行Having筛选,因此必须先对Customer和Orders的关联查询以Customer.Id进行分组,得到Customer.Id和Order数量作为属性的对象的集合,对这个集合执行linq查询,得到订单数量大于2的客户Id集合,最后用Restrictions.In方法对Customer对象集合进行筛选,选出Customer.Id在订单数量大于2的客户Id集合内的客户信息。这样就能够实现Having的查询功能。

结语

NHibernate Criteria查询优点是完全面向对象,ICriteria对象提供了大量的API函数实现完全面向对象的查询语句。可以在编译时发现问题。在更改实体类属性后(如果改动不大),不怎么需要修改查询语句。缺点是功能有限,写复杂的分组查询和条件查询比较困难。一般情况下,在写简单查询的时候用Criteria查询,在写复杂查询的时候使用HQL或者Linq to NHibernate。

NHibernate系列文章二十三:NHibernate查询之Criteria查询(附程序下载)的更多相关文章

  1. NHibernate系列文章二十五:NHibernate查询之Query Over查询(附程序下载)

    摘要 这一篇文章介绍在NHibernate 3.2里引入的Query Over查询,Query Over查询跟Criteria查询类似.首先创建IQueryOver对象,然后通过调用该对象的API函数 ...

  2. NHibernate系列文章二十二:NHibernate查询之HQL查询(附程序下载)

    摘要 NHibernate提供了多种查询方式,最早的HQL语言查询.Criteria查询和SQL Query,到NHibernate 3.0的Linq NHibernate,NHIbernate 4. ...

  3. NHibernate系列文章二十六:NHibernate查询之SQL Query查询(附程序下载)

    摘要 NHibernate在很早的版本就提供了SQL Query(原生SQL查询),对于很复杂的查询,如果使用其他的查询方式实现比较困难的时候,一般使用SQL Query.使用SQL Query是基于 ...

  4. NHibernate系列文章二:创建NHibernate工程

    摘要 这篇文章介绍了如何创建一个简单的使用NHibernate的控制台应用程序,包括使用NuGet.简单的配置.单表映射.对NHibernate配置文件添加智能提示.使用ISessionFactory ...

  5. NHibernate系列文章二十一:延迟加载

    摘要 NHibernate的延迟加载机制是很重要的内容.通过关系映射将数据库表之间的关系映射成对象之间的关系,如果没有延迟加载机制,从主表的一个对象的查询将直接查询出所有与该对象关联的其他对象,如果关 ...

  6. NHibernate系列文章一:NHibernate介绍

    摘要 NHibernate是一个成熟的开源的面向对象的.net映射框架.大量的实际项目中正在使用该框架.他是建立在ADO.Net基础之上.目前的版本是NHibernate 4.0.4.本系列文章都是基 ...

  7. NHibernate系列文章九:NHibernate对象二级缓存上

    摘要 NHibernate的二级缓存由SessionFactory管理,由所有Session共享. NHibernate缓存读取顺序: 首先从一级缓存中读取,如果一级缓存对象存在,则读取一级缓存对象并 ...

  8. NHibernate系列文章十七:NHibernate Session管理(附程序下载)

    摘要 NHibernate的Session的管理涉及到NHibernate的两个最重要的对象ISessionFactory和ISession.ISessionFactory的生成非常消耗资源,通常都在 ...

  9. NHibernate系列文章八:NHibernate对象一级缓存

    摘要 Nhibernatea缓存非常强大,按照缓存存储在Session对象还是SessionFactory对象分为一级缓存和二级缓存. 一级缓存存在于Session对象里,也叫Session缓存,由S ...

随机推荐

  1. 更新日志(建议升级到2016.12.17) && 更新程序的方法

    更新程序的方法: 1,在控制面板里点击备份当前数据库文件到磁盘,把当天获取的信息从内存写到磁盘/存储卡.2,下载最新版的源码 wget -O "infopi.zip" " ...

  2. malloc分配的内存空间是连续的吗

    1.linux内核管理内存空间的分配,所有程序对内存空间的申请和其他操作,最终都会交给内核来管理. 2.linux实现的是“虚拟内存系统”,对用户而言,所有内存都是虚拟的,也就是说程序并不是直接运行在 ...

  3. createjs 入门之EaselJs 绘制图片Bitmap

    var canvas=document.getElementById('demoCanvas'); canvas.width=window.innerWidth; canvas.height=wind ...

  4. cookie欺骗

    1.什么是cookie欺骗改变cookie的值,发给服务器,就是cookie欺骗.正常情况下,受浏览器的内部cookie机制所限,每个cookie只能被它的原服务器所访问,我们操作不了原服务器. 2. ...

  5. Discuz模拟批量上传附件发帖

    简介 对于很多用discuz做资源下载站来说,一个个上传附件,发帖是很繁琐的过程.如果需要批量上传附件发帖,就需要去模拟discuz 上传附件的流程. 模拟上传 discuz 附件逻辑 dz附件储存在 ...

  6. Beta版本冲刺——day5

    No Bug 031402401鲍亮 031402402曹鑫杰 031402403常松 031402412林淋 031402418汪培侨 031402426许秋鑫 站立式会议 今日计划表 人员 工作 ...

  7. 浅入浅出EmguCv(三)EmguCv打开指定视频

    打开视频的思路跟打开图片的思路是一样的,只不过视频是由一帧帧图片组成,因此,打开视频的处理程序有一个连续的获取图片并逐帧显示的处理过程.GUI同<浅入浅出EmguCv(二)EmguCv打开指定图 ...

  8. 【转】keil+stm32+jlink利用swd方式进行printf输出

    出处:http://www.douban.com/note/248637026/ ----------------------------------------------------------- ...

  9. JS跨域解决iframe高度自适应(IE8/Firefox/Chrome适用)

    参考园友的js跨越实现,有提到三种方式: 1. 中间页代理方式,利用iframe的location.hash 参见:http://www.5icool.org/a/201203/a1129.html ...

  10. 简单的聊天室代码php+swoole

    php swoole+websocket 客户端代码 <!DOCTYPE html> <html> <head> <title></title&g ...