摘要

上一篇文章介绍了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. ALV 顶栏的按钮设定

    *&---------------------------------------------------------------------* *& Report ZHJ_TEST0 ...

  2. C++ operator 的一种不会的用法

    自认为对C++比较熟悉,突然看到一些奇怪的代码(在看网上下载的代码Sockets): class SocketAddress { public: virtual ~SocketAddress() {} ...

  3. polyfill之javascript函数的兼容写法——Array篇

    1. Array.isArray(obj) if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype. ...

  4. 原生js事件委托

    var commontop = document.getElementById("commontop");commontop.onclick = function(ev){   v ...

  5. Druid连接池初探

    Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser. Maven配置 在pom.xml文件中添加如 ...

  6. JKS TO PEM

    tomcat 的ssl 会使用到jks,而haproxy的ssl(非tcp代理方式)会使用到pem 如果从tomcat的ssl需要迁移到haproxy的ssl,就需要从jks中读取相关信息生成pem文 ...

  7. python3-day2-python基础2

    一.for循环 for循环是我们编程中非常常用的一种循环,以下就是for循环在python中的一些应用实例: 1.单层for循环 #!/usr/bin/env python3#-*- coding: ...

  8. TextBlock

    一.TextBlock与Lable TextBlock是比Lable更底层的控件如果用TextBlock可以完成的需求就尽量不用Lable可以稍微提升一点性能. 参考文档 二.TextBlock内容过 ...

  9. navicat连接My SQL时忘记root密码处理方法

    前端时间安装完My SQL5.6以后很长时间没用过,用navicat连接时有错误提示 应该是密码错误了,但是忘记了root的密码. 在网上找了很久,终于找到修改root密码的方法并修改成功. 1. 关 ...

  10. [经验交流] Mesos-dns 和 Marathon-lb 简要使用方法

    Mesos-dns 和 Marathon-lb 是mesosphere 官网提供的两种服务发现和负载均衡工具.官方的文档主要针对DCOS,针对其它系统的相关中文文档不多,下面是我在Centos7上的安 ...