摘要
NHibernate在很早的版本就提供了SQL Query(原生SQL查询),对于很复杂的查询,如果使用其他的查询方式实现比较困难的时候,一般使用SQL Query。使用SQL Query是基于原生的SQL语句,查询后将结果做投影到NHibernate实体类对象的过程。也可以投影到其他任何.net集合类。
本篇文章的代码可以到NHibernate查询下载
1、from子句
1 public IList<Customer> GetAllSQL() 2 { 3 return Session.CreateSQLQuery("select * from Customer").AddEntity(typeof(Customer)).List<Customer>(); 4 }
首先创建调用ISession.CreateSQLQuery方法,传入原生的SQL语句,生成ISQLQuery对象,这是使用SQL Query的第一步。
ISQLQuery.AddEntity方法传入类型参数,将查询结果映射到Customer类。
ISQLQuery.List方法立即执行,返回查询结果。
2、as子句提供别名,as可以省略
1 public IList<Customer> GetAllSQL() 2 { 3 return Session.CreateSQLQuery("select * from Customer as c").AddEntity(typeof(Customer)).List<Customer>(); 4 }
3、指定列返回数组
1 public IList<int> SelectIdSQL() 2 { 3 return Session.CreateSQLQuery("select distinct c.Id from Customer c") 4 .AddScalar("Id", NHibernateUtil.Int32) 5 .List<int>(); 6 }
ISQLQuery.AddScalar方法将查询语句的列映射到.net数据类型,传入的第一个参数是列名,第二个参数是类型,NHibernateUtil类中的公开了很多静态实例对象表示映射数据类型,这里使用Int32。
4、where子句
1 public IList<Customer> GetCustomerByNameSQL(string firstName, string lastName) 2 { 3 return Session.CreateSQLQuery("select * from Customer where FirstName = :firstName and LastName = :lastName") 4 .AddEntity(typeof(Customer)) 5 .SetString("firstName", firstName) 6 .SetString("lastName", lastName) 7 .List<Customer>(); 8 } 9 10 public IList<Customer> GetCustomersStartWithSQL() 11 { 12 return Session.CreateSQLQuery("select * from Customer where FirstName like 'J%'") 13 .AddEntity(typeof(Customer)) 14 .List<Customer>(); 15 }
SQL Query的查询参数传递跟HQL参数传递是一样的。而且这里是使用原生的SQL语句,比HQL更方便。
5、order by子句
1 public IList<Customer> GetCustomersOrderBySQL() 2 { 3 return Session.CreateSQLQuery("select * from Customer c order by c.FirstName") 4 .AddEntity(typeof(Customer)) 5 .List<Customer>(); 6 }
6、关联查询
1 /// <summary> 2 /// 按分组查询客户Id及客户关联的订单数量 3 /// </summary> 4 /// <returns></returns> 5 public IList<object[]> SelectOrderCountSQL() 6 { 7 return Session.CreateSQLQuery("select c.Id, count(*) as OrderCount from Customer c inner join [Order] o on c.Id=o.CustomerId group by c.Id") 8 .AddScalar("Id", NHibernateUtil.Int32) 9 .AddScalar("OrderCount", NHibernateUtil.Int32) 10 .List<object[]>(); 11 } 12 13 /// <summary> 14 /// 查询所有订单数量大于2的客户信息 15 /// </summary> 16 /// <returns></returns> 17 public IList<Customer> GetCustomersOrderCountGreaterThanSQL() 18 { 19 string sql = @"select * from Customer 20 where Id in 21 ( 22 select c.Id from Customer c inner join [Order] o on c.Id = o.CustomerId 23 group by c.Id 24 having count(*) > 2 25 )"; 26 return Session.CreateSQLQuery(sql) 27 .AddEntity(typeof(Customer)) 28 .List<Customer>(); 29 } 30 31 /// <summary> 32 /// 查询在指定日期到当前时间内有下订单的客户信息 33 /// </summary> 34 /// <param name="orderDate"></param> 35 /// <returns></returns> 36 public IList<Customer> GetCustomersOrderDateGreatThanSQL(DateTime orderDate) 37 { 38 return Session.CreateSQLQuery("select distinct c.* from Customer c inner join [Order] o on c.Id=o.CustomerId where o.Ordered > :orderDate") 39 .AddEntity(typeof(Customer)) 40 .SetDateTime("orderDate", orderDate) 41 .List<Customer>(); 42 }
注意这几个方法都是传入的原生SQL语句,不管多复杂的查询,只要会写SQL语句,就能够使用SQL Query返回对象集合。
如果是多个表的联合查询,返回结果的字段来自不同的表,这种情况我一般是使用Hashtable映射。使用SetResultTransformer(Transformers.AliasToEntityMap)将结果映射成EntityMap,然后调用List<Hashtable>()方法返回查询结果,查询方法返回的结果类型是IList<Hashtable>。
ISQLQuery.SetResultTransformer(Transformers.AliasToEntityMap)
结语
对于复杂的多表联合查询,以及复杂的分组查询,应该使用SQL Query,因为使用它更方便,而且不容易出错。虽然在效率上,比使用其他的方式要略低。但是前提是项目只打算用SQL Server数据库或只用Oracle数据库,因为是使用的原生SQL语句,而SQL Server数据库和Oracle数据库在写查询的时候还是有很多语法上的差别。
作者:丹尼大叔
出处:http://www.cnblogs.com/uncle_danny
本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。