丹尼大叔

数学专业毕业,爱上编程的大叔,兴趣广泛。使用博客园这个平台分享我工作和业余的学习内容,以编程交友。有朋自远方来,不亦乐乎。

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

摘要

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

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

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

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

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

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

2、CreateAlias方法创建别名

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

3、指定对象返回数组

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

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

4、添加查询条件

 1         public IList<Customer> GetCustomerByNameCriteria(string firstName, string lastName)
 2         {
 3             return Session.CreateCriteria<Customer>()
 4                 .Add(Restrictions.And(
 5                             Restrictions.Eq("FirstName", firstName), Restrictions.Eq("LastName", lastName))
 6                         ).List<Customer>();
 7         }
 8 
 9         public IList<Customer> GetCustomersStartWithCriteria()
10         {
11             var list = Session.CreateCriteria<Customer>().Add(Restrictions.Like("FirstName", "J%")).List<Customer>();
12             return list.ToList();
13         }

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

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

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

6、关联查询

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

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

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

            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)查询在指定日期到当前内所有下订单客户信息

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

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

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

 1         public IList<Customer> GetCustomersOrderCountGreaterThanCriteria()
 2         {
 3             var query = Session.CreateCriteria(typeof(Customer)).CreateCriteria("Orders")
 4                             .SetProjection(Projections.ProjectionList()
 5                             .Add(Projections.GroupProperty("Id"))
 6                             .Add(Projections.RowCount()));
 7             IList<object[]> groups = query.List<object[]>();
 8 
 9             IList<int> ids = groups.Where(g => (int)g[1] > 2).Select(g => (int)g[0]).ToList();
10 
11             return Session.CreateCriteria(typeof(Customer))
12                        .Add(Restrictions.In("Id", ids.ToArray<int>()))
13                        .List<Customer>();
14         }

因为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。

posted on 2016-07-22 23:58  丹尼大叔  阅读(1085)  评论(0编辑  收藏  举报