寫在前面html
文檔與系列文章sql
多對多關係關聯查詢數據庫
總結緩存
上篇文章介紹了nhibernate中對一對多關係進行關聯查詢的幾種方式,以及在使用過程須要注意的問題。這篇文章對多對多關係的查詢處理也採用上篇文章的描述方式進行說明。session
[NHibernate]ISessionFactory配置app
[NHibernate]持久化類(Persistent Classes)sqlserver
[NHibernate]集合類(Collections)映射 學習
[NHibernate]緩存(NHibernate.Caches)
[NHibernate]NHibernate.Tool.hbm2net
[NHibernate]Nhibernate如何映射sqlserver中image字段
[NHibernate]條件查詢Criteria Query
多對多關係很是常見,好比系統中經常使用的權限管理問題,一個用戶有多個權限,固然一個權限能夠屬於多個用戶(這樣描述只是爲了對多對多關係有個感性的認識)。那麼在我們的客戶/訂單/產品,這三張表中有沒有多對多的關係呢?
訂單能夠有多個產品,一種產品能夠屬於多個訂單(這個地方有點繞,若是再有一個數量的字段,比較好理解,下一個訂單,只是庫存減小了,但id仍是那個id)。關係圖以下:
其中表TB_OrderProduct爲order和product的關係表,字段OrderID和ProductID爲聯合主鍵。
添加聯合主鍵的sql語句以下:
1 ALTER TABLE tb_orderproduct WITH NOCHECK ADD 2 CONSTRAINT [PK_orderproduct] PRIMARY KEY NONCLUSTERED 3 ( 4 orderid, 5 productid 6 )
首先修改Order類
1 /// <summary> 2 /// 描述:訂單實體,數據庫持久化類 3 /// 建立人:wolfy 4 /// 建立時間:2014-10-16 5 /// </summary> 6 public class Order 7 { 8 /// <summary> 9 /// 訂單id 10 /// </summary> 11 public virtual Guid OrderID { set; get; } 12 /// <summary> 13 /// 下訂單時間 14 /// </summary> 15 public virtual DateTime OrderDate { set; get; } 16 /// <summary> 17 /// 下訂單的客戶,多對一的關係:orders對應一個客戶 18 /// </summary> 19 public virtual Customer Customer { set; get; } 20 /// <summary> 21 /// 多對多關係,一個訂單下能夠有多個產品 22 /// </summary> 23 public virtual IList<Product> Products { set; get; } 24 }
修改Order.hbm.xml映射文件以下
1 <?xml version="1.0" encoding="utf-8" ?> 2 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Wolfy.Shop.Domain" namespace="Wolfy.Shop.Domain.Entities"> 3 <class name="Wolfy.Shop.Domain.Entities.Order,Wolfy.Shop.Domain" table="TB_Order"> 4 <id name="OrderID" column="OrderID" type="Guid" unsaved-value="null"> 5 <generator class="assigned" /> 6 </id> 7 <property name="OrderDate" column="OrderDate" type="DateTime" 8 not-null="true" /> 9 <!--多對一關係:Orders屬於一個Customer--> 10 <many-to-one name="Customer" column="CustomerID" not-null="true" 11 class="Wolfy.Shop.Domain.Entities.Customer,Wolfy.Shop.Domain" 12 foreign-key="FK_TB_Order_TB_Customer" /> 13 <!--多對多關係:order下有多個product--> 14 <bag name="Products" generic="true" table="TB_OrderProduct"> 15 <key column="OrderID" foreign-key="FK_TB_OrderProduct_TB_Order"/> 16 <many-to-many column="ProductID" class="Wolfy.Shop.Domain.Entities.Product,Wolfy.Shop.Domain" 17 foreign-key="FK_TB_OrderProduct_TB_Product"/> 18 19 </bag> 20 </class> 21 </hibernate-mapping>
修改Product類
1 /// <summary> 2 /// 描述:商品實體,數據庫持久化類 3 /// 建立人:wolfy 4 /// 建立時間:2014-10-16 5 /// </summary> 6 public class Product 7 { 8 /// <summary> 9 /// 商品id 10 /// </summary> 11 public virtual Guid ProductID { set; get; } 12 /// <summary> 13 /// 商品名稱 14 /// </summary> 15 public virtual string Name { set; get; } 16 /// <summary> 17 /// 商品單價 18 /// </summary> 19 public virtual decimal Price { set; get; } 20 /// <summary> 21 /// 多對多關係:Product屬於多個Orders 22 /// </summary> 23 public virtual IList<Order> Orders { get; set; } 24 25 }
Mappings文件夾中新建Product.hbm.xml映射文件
1 <?xml version="1.0" encoding="utf-8" ?> 2 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Wolfy.Shop.Domain" namespace="Wolfy.Shop.Domain.Entities"> 3 <class name="Wolfy.Shop.Domain.Entities.Product,Wolfy.Shop.Domain" table="TB_Product"> 4 <id name="ProductID" column="ProductID" type="Guid" unsaved-value="null"> 5 <generator class="assigned" /> 6 </id> 7 <property name="Name" column="Name" type="String" 8 not-null="true" /> 9 <property name="Price" column="Price" type="float" 10 not-null="true" /> 11 <!--多對多關係:product屬於多個orders--> 12 <bag name="Orders" generic="true" table="TB_OrderProduct"> 13 <key column="ProductID" foreign-key="FK_TB_OrderProduct_TB_Product"/> 14 <many-to-many column="OrderID" class="Wolfy.Shop.Domain.Entities.Order,Wolfy.Shop.Domain" 15 foreign-key="FK_TB_OrderProduct_TB_Order"/> 16 </bag> 17 </class> 18 </hibernate-mapping>
修改映射文件的屬性,這個動做應該養成一個習慣,無論你寫的配置文件對不對,只要添加了映射文件,就修改它的屬性,如圖:
經過上面對比,你會發現多對多關係many-to-many節點的配置類似,只是方向有點區別。
原生SQL查詢
查詢客戶的全部的訂單和訂單下全部的產品。
CustomerData.cs
1 /// <summary> 2 /// 經過sql查詢客戶下的訂單和產品信息 3 /// </summary> 4 /// <param name="cutomerID"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomerOrderProductsBySQL(Guid cutomerID) 7 { 8 //得到ISession實例 9 ISession session = NHibernateHelper.GetSession(); 10 //使用inner join關聯多個表進行查詢 11 return session.CreateSQLQuery("select distinct c.* from TB_Customer c" + 12 " inner join TB_Order o on o.CustomerID=c.CustomerID" + 13 " inner join TB_OrderProduct op on o.OrderID=op.OrderID" + 14 " inner join TB_Product p on op.ProductID=p.ProductID where c.CustomerID=:CustomerID") 15 //使用AddEntity設置返回的實體。 16 .AddEntity("Customer", typeof(Customer)) 17 .SetGuid("CustomerID", cutomerID) 18 .List<Customer>(); 19 }
生成的sql語句
HQL查詢
查詢客戶的全部的訂單和訂單下全部的產品。
CustomerData.cs
1 /// <summary> 2 /// 經過HQL查詢客戶下的訂單和產品信息 3 /// </summary> 4 /// <param name="cutomerID"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomerOrderProductsByHQL(Guid cutomerID) 7 { 8 //得到ISession實例 9 ISession session = NHibernateHelper.GetSession(); 10 //使用HQL基於面向對象的查詢方式 11 return session.CreateQuery("select distinct c from Customer c inner join c.Orders o inner join o.Products where c.CustomerID=:CustomerID") 12 .SetGuid("CustomerID", cutomerID) 13 .List<Customer>(); 14 }
生成的sql語句
經過查看sql及HQL語句能夠知道,c.Orders o inner join o.Products 內部爲咱們查詢了全部Order下的全部產品,你會發現咱們的查詢中並無出現表TB_OrderProduct,而在sql語句中出現了該表,由於這些信息在映射文件已經描述了。nhibernate經過映射文件,知道如何關聯,該關聯那張數據表。
public IList<Customer> UseHQL_GetCustomersWithOrdersHavingProduct(DateTime orderDate) { return _session.CreateQuery("select distinct c from Customer c ," + " c.Orders.elements o where o.OrderDate > :orderDate") .SetDateTime("orderDate", orderDate) .List<Customer>(); }
上面這段代碼是@李永京文章中的,這種方式也嘗試了c.Orders.elements,老是報如下異常:
NHibernate.Hql.Ast.ANTLR.QuerySyntaxException : c.Orders.elements is not mapped [select distinct c from Customer c , c.Orders.elements o where o.OrderDate > :orderDate]
也許,大概elements在nhibernate 4.0版本中廢除了吧,最後沒辦法,就經過我上面寫的那種方式實現了HQL查詢,畢竟條條大路通羅馬,不能在一條路上吊死吧。
Criteria API關聯查詢
經過HQL方式,咱們已經知道了實體間的關係已經在映射文件中定義好了,因此咱們在查詢子對象使用子CreateCriteria語句關聯對象之間導航,能夠很容易地在實體之間指定約束。這裏第二個CreateCriteria()返回ICriteria的新實例,並指向Orders實體的元素。第三個指向Products實體的元素。
查詢客戶的全部的訂單和訂單下全部的產品。
CustomerData.cs
1 /// <summary> 2 /// 經過HQL查詢客戶下的訂單和產品信息 3 /// </summary> 4 /// <param name="cutomerID"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomerOrderProductsByCriteriaAPI(Guid cutomerID) 7 { 8 //得到ISession實例 9 ISession session = NHibernateHelper.GetSession(); 10 return session.CreateCriteria(typeof(Customer)) 11 .Add(Restrictions.Eq("CustomerID", cutomerID)) 12 .CreateCriteria("Orders") 13 .CreateCriteria("Products") 14 .List<Customer>(); 15 }
生成的sql語句
此時查詢出來的數據有兩條,由於有兩個產品,沒有對其進行去重。
測試數據以下:
TB_Customer表
TB_Order表
TB_OrderProduct表
TB_Product表
在學習多對多關聯查詢時,在c.Orders.elements的地方卡在那個地方了,這塊還須要在查一查nhibernate版本之間是否是有差別。被一個問題,折騰到如今,原本打算十點半睡覺的(天天最晚十點半上牀睡覺),我基本是不熬夜的,有點強迫症,不想帶着問題睡覺,很晚了,就寫到這兒吧。
參考地址:http://www.cnblogs.com/lyj/archive/2008/10/27/1320764.html#!comments