NHibernate之旅(10):探索父子(一对多)关联查询
本節內容
- 關聯查詢引入
- 一對多關聯查詢
- 1.原生SQL關聯查詢
- 2.HQL關聯查詢
- 3.Criteria API關聯查詢
- 結語
關聯查詢引入
在NHibernate中提供了三種查詢方式給我們選擇:NHibernate查詢語言(HQL,NHibernate Query Language)、條件查詢(Criteria API,Query By Example(QBE)是Criteria API的一種特殊情況)、原生SQL(Literal SQL,T-SQL、PL/SQL)。這一節分別使用這三種方式來關聯查詢。
首先看看上一篇我們為Customer和Order建立的父子關系:
一對多關聯查詢
1.原生SQL關聯查詢
在關系模型中:可以使用子表作為內連接查詢Customer,像這樣:
select * from Customer c inner join Order o on c.CustomerId=o.CustomerId where o.CustomerId=<id of the Customer>
使用父表作為內連接查詢Order,像這樣:
select * from Oder o inner join Customer c on o.CustomerId=c.CustomerId where o.OrderId=<id of the Order>
下面我們來看看在NHibernate中使用原生SQL查詢。這篇來完成查詢訂單在orderData之后的顧客列表不同查詢的寫法。
public IList<Customer> UseSQL_GetCustomersWithOrders(DateTime orderDate) {return _session.CreateSQLQuery("select distinct {customer.*} from Customer {customer}"+" inner join [Order] o on o.Customer={customer}.CustomerId where o.OrderDate> :orderDate").AddEntity("customer", typeof(Customer)).SetDateTime("orderDate", orderDate).List<Customer>(); }具體情況是:實例化IQuery接口;使用ISession.CreateSQLQuery()方法,傳遞的參數是SQL查詢語句;{Customer.*}標記是Customer所有屬性的簡寫。 使用AddEntity查詢返回的持久化類,SetDataTime設置參數,根據不同類型,方法名不同。
2.HQL關聯查詢
查詢訂單在orderData之后的顧客列表的HQL關聯查詢寫法:
public IList<Customer> UseHQL_GetCustomersWithOrders(DateTime orderDate) {return _session.CreateQuery("select distinct c from Customer c inner join c.Orders o where o.OrderDate > :orderDate").SetDateTime("orderDate", orderDate).List<Customer>(); }這里使用基于面向對象的HQL,一目了然,符合面向對象編程習慣。
寫個測試用例測試UseHQL_GetCustomersWithOrdersTest()查詢方法是否正確:
[Test] public void UseHQL_GetCustomersWithOrdersTest() {IList<Customer> customers = _relation.UseHQL_GetCustomersWithOrders(new DateTime(2008, 10, 1));foreach (Customer c in customers){foreach (Order o in c.Orders){Assert.GreaterOrEqual(o.OrderDate, new DateTime(2008, 10, 1));}}foreach (Customer c in customers){Assert.AreEqual(1, customers.Count<Customer>(x => x == c));} }首先調用UseHQL_GetCustomersWithOrders()方法查詢訂單在2008年10月1號之后的顧客列表,遍歷顧客列表,斷言顧客為預期的1個,他的訂單時間在2008年10月1號之后。OK!測試成功。注意:這個測試用例可測試本篇所有的關聯查詢。
3.Criteria API關聯查詢
我們使用CreateCriteria()在關聯之間導航,很容易地在實體之間指定約束。這里第二個CreateCriteria()返回一個ICriteria的新實例,并指向Orders實體的元素。在查詢中子對象使用子CreateCriteria語句,這是因為實體之間的關聯我們在映射文件中已經定義好了。還有一種方法使用CreateAlias()不會創建ICriteria的新實例。
這個例子返回顧客列表有重復的,不是我們想要的結果。
public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate) {return _session.CreateCriteria(typeof(Customer)).CreateCriteria("Orders").Add(Restrictions.Gt("OrderDate", orderDate)).List<Customer>(); }預過濾
使用ICriteria接口的SetResultTransformer(IResultTransformer resultTransformer)方法返回滿足特定條件的Customer。上面例子中使用條件查詢,觀察其生成的SQL語句并沒有distinct,這時可以使用NHibernate.Transform命名空間中的方法或者使用NHibernate提供的NHibernate.CriteriaUtil.RootEntity、NHibernate.CriteriaUtil.DistinctRootEntity、NHibernate.CriteriaUtil.AliasToEntityMap靜態方法實現預過濾的作用。那么上面的查詢應該修改為:
public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate) {return _session.CreateCriteria(typeof(Customer)).CreateCriteria("Orders").Add(Restrictions.Gt("OrderDate", orderDate)).SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())//或者.SetResultTransformer(NHibernate.CriteriaUtil.DistinctRootEntity).List<Customer>(); }這個例子從轉換結果集的角度實現了我們想要的效果。
投影
調用SetProjection()方法可以實現應用投影到一個查詢中。NHibernate.Criterion.Projections是Projection的實例工廠,Projections提供了非常多的方法,看看下面的截圖,下拉列表中的方法是不是很多啊:
現在可以條件查詢提供的投影來完成上面同樣的目的:
public IList<Customer> UseCriteriaAPI_GetDistinctCustomers(DateTime orderDate) {IList<int> ids = _session.CreateCriteria(typeof(Customer)).SetProjection(Projections.Distinct(Projections.ProjectionList().Add(Projections.Property("CustomerId")))).CreateCriteria("Orders").Add(Restrictions.Gt("OrderDate", orderDate)).List<int>();return _session.CreateCriteria(typeof(Customer)).Add(Restrictions.In("CustomerId", ids.ToArray<int>())).List<Customer>(); }我們可以添加若干的投影到投影列表中,例如這個例子我添加一個CustomerId屬性值到投影列表中,這個列表中的所有屬性值都設置了Distinct投影,第一句返回訂單時間在orderDate之后所有顧客Distinct的CustomerId,第二句根據返回的CustomerId查詢顧客列表。達到上面的目的。這時發現其生成的SQL語句中有distinct。我們使用投影可以很容易的組合我們需要的各種方法。
結語
這一篇通過上一篇完成的一對多關系映射,使用NHibernate中提供的三種查詢方法實現了父子關聯查詢,并初步探討了條件查詢中比較深入的話題。希望對你有所幫助。下一篇開始討論NHibernate中的多對多映射關系和查詢。
本系列鏈接:NHibernate之旅系列文章導航
NHibernate Q&A- 歡迎加入NHibernate中文社區,一起討論NHibernate知識!
- 請到NHibernate中文社區下載本系列相關源碼。
下次繼續分享NHibernate!
轉載于:https://www.cnblogs.com/lyj/archive/2008/10/26/1319889.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的NHibernate之旅(10):探索父子(一对多)关联查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Internet Explorer 8
- 下一篇: ArcGIS.Server.9.3和Ar