目錄
寫在前面
上篇文章介紹了nhibernate的一對多關系如何配置,以及級聯刪除,級聯添加數據的內容。這篇文章我們將學習nhibernate中的一對多關系的關聯查詢。前面文章中也介紹的nhibernate的查詢:HQL,條件查詢,原生SQL查詢。
文檔與系列文章
[NHibernate]持久化類(Persistent Classes)
[NHibernate]集合類(Collections)映射
[NHibernate]緩存(NHibernate.Caches)
[NHibernate]NHibernate.Tool.hbm2net
[NHibernate]Nhibernate如何映射sqlserver中image字段
[NHibernate]條件查詢Criteria Query
一對多查詢
原生sql關聯查詢
查詢某一個客戶的信息,以及該客戶所下的訂單信息
1 /// <summary> 2 /// 查詢某客戶信息與該客戶的訂單信息 3 /// </summary> 4 /// <param name="customerID"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomerOrders(Guid customerID) 7 { 8 //獲得ISession實例 9 ISession session = NHibernateHelper.GetSession(); 10 //實例化IQuery接口;使用ISession.CreateSQLQuery()方法,傳遞的參數是SQL查詢語句 11 return session.CreateSQLQuery("select distinct tb_customer.*,tb_order.* from tb_customer " 12 + "inner join tb_order on tb_customer.customerid=tb_order.customerid where tb_customer.customerid=:id") 13 .AddEntity("Customer", typeof(Customer)) 14 .SetGuid("id", customerID) 15 .List<Customer>(); 16 }
注意,此時使用的是真正的sql,里面使用的是數據表,這點與hql不同(hql中使用的是面向對象的概念,使用的是數據表映射的實體類對象)。
1 /// <summary> 2 /// 按客戶id查詢客戶信息及訂單信息 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 protected void btnSearchByID_Click(object sender, EventArgs e) 7 { 8 Business.CustomerBusiness customerBusiness = new Business.CustomerBusiness(); 9 this.rptCustomerList.DataSource = customerBusiness.GetCustomerOrders(new Guid("B0720295-9541-40B3-9994-610066224DB8")); 10 this.rptCustomerList.DataBind(); 11 }
生成的sql語句,因為使用的inner join ,測試的數據為一個客戶對應的訂單有2個,所以查詢出來的數據有2條。
HQL關聯查詢
使用HQL查詢,某一個客戶的信息,以及該客戶所下的訂單信息
1 /// <summary> 2 /// HQL查詢某客戶信息與該客戶的訂單信息 3 /// </summary> 4 /// <param name="customerID"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomerOrdersByHQL(Guid customerID) 7 { 8 //獲得ISession實例 9 ISession session = NHibernateHelper.GetSession(); 10 return session.CreateQuery("select c from Customer c inner join c.Orders where c.CustomerID=:id") 11 .SetGuid("id", customerID) 12 .List<Customer>(); 13 }
通過觀察,可以發現inner join 后面的Orders為實體Customer的一個屬性,這種面向對象的方式更符合咱們的開發習慣。
生成的sql語句為
Criteria API條件查詢
使用Criteria API條件查詢,某一個客戶的信息,以及該客戶所下的訂單信息
使用CreateCriteria()在關聯之間導航,很容易地在實體之間指定約束。這里第二個CreateCriteria()返回一個ICriteria的新實例,並指向Orders實體的元素。在查詢中子對象使用子CreateCriteria語句,這是因為實體之間的關聯我們在映射文件中已經定義好了。
還有一種方法使用CreateAlias()不會創建ICriteria的新實例。
1 /// <summary> 2 /// Criteria API查詢某客戶信息與該客戶的訂單信息 3 /// </summary> 4 /// <param name="customerID"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomerOrdersByCriteria(Guid customerID) 7 { 8 //獲得ISession實例 9 ISession session = NHibernateHelper.GetSession(); 10 return session.CreateCriteria(typeof(Customer)) 11 .CreateCriteria("Orders") 12 .Add(Restrictions.Eq("Customer.CustomerID", customerID)) 13 .List<Customer>(); 14 }
這個地方需要注意因為在Order和Customer實體中都有CustomerID屬性,需要指明是哪個CustomerID。
生成的sql
這種方式得到的結果可能重復,可通過如下方式進行預過濾
預過濾
使用ICriteria接口的SetResultTransformer(IResultTransformer resultTransformer)方法返回滿足特定條件的Customer。上面例子中使用條件查詢,觀察其生成的SQL語句並沒有distinct,這時可以使用NHibernate.Transform命名空間中的方法或者使用NHibernate提供的NHibernate.CriteriaUtil.RootEntity、NHibernate.CriteriaUtil.DistinctRootEntity、NHibernate.CriteriaUtil.AliasToEntityMap靜態方法實現預過濾的作用。那么上面的查詢應該修改為:
1 /// <summary> 2 /// Criteria API查詢某客戶信息與該客戶的訂單信息 3 /// </summary> 4 /// <param name="customerID"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomerOrdersByCriteria(Guid customerID) 7 { 8 //獲得ISession實例 9 ISession session = NHibernateHelper.GetSession(); 10 return session.CreateCriteria(typeof(Customer)) 11 .CreateCriteria("Orders") 12 .Add(Restrictions.Eq("Customer.CustomerID", customerID)) 13 //預過濾重復的結果 14 .SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer()) 15 //或者.SetResultTransformer(NHibernate.CriteriaUtil.DistinctRootEntity) 16 .List<Customer>(); 17 }
生成的sql語句
沒預過濾的
使用預過濾的
此時查詢的Order為一條。通過對比你會發現他們生成的sql語句一樣,真正實現過濾的應該是在內存中做的。
投影
調用SetProjection()方法可以實現應用投影到一個查詢中。NHibernate.Criterion.Projections是Projection的實例工廠,Projections提供了非常多的方法。
1 /// <summary> 2 /// 投影查詢某客戶信息與該客戶的訂單信息 3 /// </summary> 4 /// <param name="customerID"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomerOrdersByProjection(Guid customerID) 7 { 8 //獲得ISession實例 9 ISession session = NHibernateHelper.GetSession(); 10 IList<Guid> ids = session.CreateCriteria(typeof(Customer)) 11 .SetProjection(Projections.Distinct( 12 Projections.ProjectionList() 13 .Add(Projections.Property("CustomerID")) 14 ) 15 ) 16 .CreateCriteria("Orders") 17 .Add(Restrictions.Eq("Customer.CustomerID", customerID)) 18 .List<Guid>(); 19 return session.CreateCriteria(typeof(Customer)) 20 .Add(Restrictions.In("CustomerID", ids.ToArray<Guid>())) 21 .List<Customer>(); 22 }
我們可以添加若干的投影到投影列表中,例如這個例子我添加一個CustomerId屬性值到投影列表中,這個列表中的所有屬性值都設置了Distinct投影,第一句返回訂單的客戶CustomerId,第二句根據返回的CustomerId查詢顧客列表。達到上面的目的。這時發現其生成的SQL語句中有distinct。我們使用投影可以很容易的組合我們需要的各種方法。
生成的sql語句
總結
這里介紹了處理一對多關系的關聯查詢的方式,希望對你有所幫助。
參考地址:http://www.cnblogs.com/lyj/archive/2008/10/26/1319889.html