摘要

上一篇文章介绍了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. C++ 数字转字符串

    #include <sstream> string num2str( int i) { stringstream ss; ss<<i; return ss.strs(); }

  2. 关于分布式事务的一个误解:使用了TransactionScope就一定会开启分布式事务吗?

    背景: 事务是数据库管理系统的一个基本概念,事务具有四个基本特点,即ACID:原子性(Atomicity).一致性(Consistency).隔离性(Isolation)和持久性(Durability ...

  3. 获取tp-link中的拨号密码

    一日,公司网络巨慢,丢包非常严重,打电话给电信,说信号稳定,可能是我们的路由器有问题,让我们直接用电脑拨号 心中一闷,鬼知道拨号密码是多少,于是百度了一下,大概有以下几种方法 一.使用工具,把路由器的 ...

  4. AI(二):人脸识别

    微软提供的人脸识别服务可检测图片中一个或者多个人脸,并为人脸标记出边框,同时还可获得基于机器学习技术做出的面部特征预测.可支持的人脸功能有:年龄.性别.头部姿态.微笑检测.胡须检测以及27个面部重要特 ...

  5. 加密配置文件(App.Config和Web.config)中connectionStrings通用方法

    1. 背景:根据项目的要求,需要对配置文件配置的数据库连接字符串进行加密,也就是对ConnectinString节点的内容进行加密存储,同时考虑到代码使用连接字符串不需要进行更改,C#会自动对加密的内 ...

  6. Alembic

    Layers of the Library:  AbcA(low)  -->  Abc  -->  AbcGeom(high) Container Hierarchy in Alembic ...

  7. Ubuntu 13.10看视频休眠

    cat <<EOF | sudo tee /etc/polkit-1/localauthority/50-local.d/com.ubuntu.enable-hibernate.pkla[ ...

  8. Node.js基础与实战

    Node.js基础与实战 Node.jsJS高级进阶 NODE原理与解析 REPL交互环境 模块与NPM Buffer缓存区 fs文件操作 Stream流 TCP&UDP 异步编程 HTTP& ...

  9. C# webbrowser实现真正意义上的F5刷新

    关于webbrowser的刷新在C#中有提供方便的方法: webbrowser.refresh(); 但是有时候会发现,不给力啊 那怎么办? 还有一招: webBrowser1.Document.Ex ...

  10. python 类变量和实例变量

    super(cls, inst) 获得的是 cls 在 inst 的 MRO 列表中的下一个类.  实例的属性存储在实例的__dict__中,类属性和方法存储在类的__dict__中.查找属性时,先检 ...