[轉]NHibernate之旅(10):探索父子(一對多)關聯查詢

來源:互聯網
上載者:User

標籤:blog   http   io   使用   ar   strong   for   檔案   cti   

本節內容

  • 關聯查詢引入
  • 一對多關聯查詢
    • 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之旅(10):探索父子(一對多)關聯查詢

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.