摘要
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數據庫在寫查詢的時候還是有很多語法上的差別。
