程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> NHibernate之旅(11):探索多對多關系及其關聯查詢

NHibernate之旅(11):探索多對多關系及其關聯查詢

編輯:關於.NET

本節內容

多對多關系引入

多對多映射關系

多對多關聯查詢

1.原生SQL關聯查詢

2.HQL關聯查詢

3.Criteria API關聯查詢

結語

多對多關系引入

讓我們再次回顧在第二篇中建立的數據模型:

在圖上,我已經清晰的標注了表之間的關系,上兩篇分析Customer和Order之間的“外鍵關系”或者稱作“父子關系”、“一對多關系”和關聯查詢,這一篇以Order為中心,分析Order和Product之間的關系,直接看下面一幅圖的兩張表:

上面兩張表關系表達的意思是:Order有多個Products,Product屬於多個Orders。我們稱Order和Product是多對多關系,這一篇我們來深入討論在NHibernate如何映射多對多關系及其多對多關聯查詢。

多對多映射關系1.Order有多個Products

有了上兩篇的基礎,現在直奔主題,建立關系。大家可以把這篇的代碼作為模板,以後在工作中參考。

修改Order.cs類代碼如下:

namespace DomainModel.Entities
{
  public class Order
  {
    public virtual int OrderId { get; set; }
    public virtual DateTime OrderDate { get; set; }
    //多對一關系:Orders屬於一個Customer
     public virtual Customer Customer { get; set; }
    //多對多關系:Order有多個Products
     public virtual IList<Product> Products { get; set; }
  }
}

修改Order.hbm.xml映射文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
          assembly="DomainModel" namespace="DomainModel">

 <class name="DomainModel.Entities.Order,DomainModel" table="`Order`" >
  <id name="OrderId" column="OrderId" type="Int32" unsaved-value="0">
   <generator class="native" />
  </id>
  <property name="OrderDate" column="OrderDate" type="DateTime" not-null="true" />
  <!--多對一關系:Orders屬於一個Customer-->
  <many-to-one name="Customer" column="Customer" not-null="true"
         class="DomainModel.Entities.Customer,DomainModel"
         foreign-key="FK_CustomerOrders" />
  <!--多對多關系:Order有多個Products-->
  <bag name="Products" generic="true" table="OrderProduct">
     <key column="`Order`" foreign-key="FK_OrderProducts"/>
     <many-to-many column="Product"
          class ="DomainModel.Entities.Product,DomainModel"
          foreign-key="FK_ProductOrders"/>
  </bag>
 </class>
</hibernate-mapping>

在多對多關系中,其兩方都使用Bag集合和many-to-many元素。看看上面各個屬性和one-to-many,many-to-one屬性差不多。

2.Product屬於多個Orders

在項目DomainModel層的Entities文件夾中新建Product.cs類,編寫代碼如下:

namespace DomainModel.Entities
{
  public class Product
  {
    public virtual int ProductId { get; set; }
    public virtual string Name { get; set; }
    public virtual float Cost { get; set; }
    //多對多關系:Product屬於多個Orders
    public virtual IList<Order> Orders { get; set; }
  }
}

在項目DomainModel層的Mappings文件夾中新建Product.hbm.xml映射文件,編寫代碼如下:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
          assembly="DomainModel" namespace="DomainModel">
 <class name="DomainModel.Entities.Product,DomainModel" table="Product">

  <id name="ProductId" column ="ProductId" type="Int32" unsaved-value="0">
   <generator class="native"/>
  </id>
  <property name="Name" column="Name" type="string" not-null="true" length="50"/>
  <property name="Cost" column="Cost" type="float" not-null="true"/>
   <!--多對多關系:Product屬於多個Orders-->
  <bag name="Orders" generic="true" table="OrderProduct">
    <key column="Product" foreign-key="FK_ProductOrders"/>
    <many-to-many column="`Order`"
          class="DomainModel.Entities.Order,DomainModel"
          foreign-key="FK_OrderProducts"/>
  </bag>
 </class>
</hibernate-mapping>

多對多關聯查詢

使用NHibernate中提供的三種查詢方法實現多對多關聯查詢,查詢返回所有訂單和產品的顧客列表。

1.原生SQL關聯查詢

public IList<Customer> UseSQL_GetCustomersWithOrdersHavingProduct(DateTime orderDate)
{
  return _session.CreateSQLQuery("select distinct {customer.*} from Customer {customer}" +
  " inner join [Order] o on o.Customer={customer}.CustomerId"+
  " inner join OrderProduct op on o.OrderId=op.[Order]"+
  " inner join Product p on op.Product=p.ProductId where o.OrderDate> :orderDate")
    .AddEntity("customer", typeof(Customer))
    .SetDateTime("orderDate", orderDate)
    .List<Customer>();
}

這裡需要使用Join告訴查詢如何在表之間關聯。無論多麼復雜的關系,我們必須在查詢語句中指定返回值。這裡使用AddEntity設置返回的實體。

2.HQL關聯查詢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>();
}

因為在映射文件已經定義實體之間一對多、多對多關系,NHibernate通過映射文件知道如何去關聯這些實體,我們不需要在查詢語句中重復定義。這裡使用查詢和上一篇使用HQL關聯查詢語句一樣,NHibernate完全可以去關聯對象,實現查詢訂單和產品。

3.Criteria API關聯查詢

因為實體之間的關聯我們在映射文件中已經定義好了。所以我們在查詢子對象使用子CreateCriteria語句關聯對象之間導航,可以很容易地在實體之間指定約束。這裡第二個CreateCriteria()返回ICriteria的新實例,並指向Orders實體的元素。第三個指向Products實體的元素。

public IList<Customer> UseCriteriaAPI_GetCustomerswithOrdersHavingProduct()
{
  return _session.CreateCriteria(typeof(Customer))
    .Add(Restrictions.Eq("Firstname","YJing"))
    .CreateCriteria("Orders")
    .Add(Restrictions.Gt("OrderDate",new DateTime(2008,10,1)))
    .CreateCriteria("Products")
    .Add(Restrictions.Eq("Name","Cnblogs"))
    .List<Customer>();
}

下面我用一幅圖簡單明了的說明這段代碼神秘之處,也顯示了一些約束條件。

編寫一個測試用例測試UseCriteriaAPI_GetCustomerswithOrdersHavingProduct()方法,遍歷列表,看看產品名稱是否為“Cnblogs”,OK!測試通過。

[Test]
public void UseCriteriaAPI_GetCustomerswithOrdersHavingProductTest()
{
  IList<Customer> customers = _relation.UseCriteriaAPI_GetCustomerswithOrdersHavingProduct();
  bool found = false;
  foreach (Customer c in customers)
  {
    foreach (Order o in c.Orders)
    {
      foreach (Product p in o.Products)
      {
        if (p.Name == "Cnblogs")
        {
          found = true;
          break;
        }
      }
    }
  }
  Assert.IsTrue(found);
}

下面再寫個簡單例子查詢產品Id所關聯的一些顧客,測試用例同上面差不多,自己修改下就可以啦。

public IList<Customer> UseCriteriaAPI_GetCustomerswithOrdersHavingProduct(int productId)
{
  return _session.CreateCriteria(typeof(Customer))
    .CreateCriteria("Orders")
    .CreateCriteria("Products")
    .Add(Restrictions.Eq("ProductId", productId))
    .List<Customer>();
}

結語

這一篇通過全盤代碼的形式完成NHibernate中的多對多關系映射,使用NHibernate中提供的三種查詢方法實現了多對多關聯查詢。希望對你有所幫助,多多練習。我們下次繼續討論NHibernate話題,像延遲加載、立即加載、對象狀態等話題,關於朋友回復說討論更多話題,我只能說,再等等吧,慢慢來,這才第十一篇,先把基礎的問題弄清楚。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved