1. 程式人生 > >NHibernate查詢語言(HQL)引數化查詢

NHibernate查詢語言(HQL)引數化查詢

http://www.cnblogs.com/lyj/archive/2008/10/15/1312089.html

NHibernate中的查詢方法

在NHibernate中提供了很多查詢方式給我們選擇,這裡僅僅列舉了3種方式:NHibernate查詢語言(HQL,NHibernate Query Language)、條件查詢(Criteria API,Query By Example(QBE)是Criteria API的一種特殊情況)、原生SQL(Literal SQL,T-SQL、PL/SQL)。每個人有不同的喜好和特長,可以根據自己的情況選擇使用其中的一種或幾種。這一節我們介紹NHibernate查詢語言(HQL,NHibernate Query Language)。

NHibernate查詢語言(HQL)

NHibernate查詢語言(HQL,NHibernate Query Language)是NHibernate特有的基於面向物件的SQL查詢語言,它具有繼承、多型和關聯等特性。實際上是用OOP中的物件和屬性映射了資料庫中的表和列。

例如這一句:select c.Firstname from Customer c

Customer是資料庫表,Firstname是列;而對於HQL:Customer是一個物件,Firstname是Customer物件的屬性。相比之下SQL語句非常靈活,但是沒有編譯時語法驗證支援。

本節介紹基礎語法:from子句,select子句,where子句,order by子句,group by子句並分別舉出可以執行的例項。至於關聯和連線,多型(polymorphism)查詢,子查詢在以後具體例項中學習。注意:HQL關鍵字不區分大小寫。

注意:由於篇幅有限,我在這裡僅僅貼出了資料訪問層的程式碼,就是在業務邏輯層可以直接呼叫的方法。測試這些方法的程式碼就沒有貼出來了,你可以下載本系列的原始碼仔細看看測試這些方法的程式碼。這節,我們在上一節原始碼的基礎上,在資料訪問層中新建QueryHql.cs類用於編寫HQL查詢方法,在資料訪問的測試層新建一QueryHqlFixture.cs類用於測試。

1.from子句

顧名思義,同SQL語句類似:

1.簡單用法:返回表中所有資料。

public IList<Customer> From()
{
    //返回所有Customer類的例項
    return _session.CreateQuery("from Customer"
) .List<Customer>(); }

2.使用別名:使用as來賦予表的別名,as可以省略。

public IList<Customer> FromAlias()
{
    //返回所有Customer類的例項,Customer賦予了別名customer
    return _session.CreateQuery("from Customer as customer")
        .List<Customer>();
}

3.笛卡爾積:出現多個類,或者分別使用別名,返回笛卡爾積或者稱為“交叉”連線。

2.select子句

1.簡單用法:在結果集中返回指定的物件和屬性。

public IList<int> Select()
{
    //返回所有Customer的CustomerId
    return _session.CreateQuery("select c.CustomerId from Customer c")
        .List<int>();
}

2.陣列:用Object[]的陣列返回多個物件和/或多個屬性,或者使用特殊的elements功能,注意一般要結合group by使用。注意,這裡是Object[]的陣列,我們可以定義DTO物件集合返回,即使用型別安全的.NET物件。

public IList<object[]> SelectObject()
{
   return _session.CreateQuery("select c.Firstname, count(c.Firstname) from Customer c group by c.Firstname")
        .List<object[]>();
}

3.統計函式:用Object[]的陣列返回屬性的統計函式的結果,注意統計函式的變數也可以是集合count( elements(c.CustomerId) ) 。注意,這裡是Object[]的陣列,我們可以定義DTO物件集合返回。

public IList<object[]> AggregateFunction()
{
    return _session.CreateQuery("select avg(c.CustomerId),sum(c.CustomerId),count(c) from Customer c")
        .List<object[]>();
}

4.Distinct用法:distinct和all關鍵字的用法和語義與SQL相同。例項:獲取不同Customer的FirstName。

public IList<string> Distinct()
{
     return _session.CreateQuery("select distinct c.Firstname from Customer c")
        .List<string>();
}

3.where子句

where子句讓你縮小你要返回的例項的列表範圍。

public IList<Customer> Where()
{
    return _session.CreateQuery("from Customer c where c.Firstname='YJing'")
        .List<Customer>();
}

where子句允許出現的表示式包括了在SQL中的大多數情況:

  • 數學操作符:+, -, *, /
  • 真假比較操作符:=, >=, <=, <>, !=, like
  • 邏輯操作符:and, or, not
  • 字串連線操作符:||  
  • SQL標量函式:upper(),lower()
  • 沒有字首的( ):表示分組
  • in, between, is null
  • 位置引數:?
  • 命名引數::name, :start_date, :x1
  • SQL文字:'foo', 69, '1970-01-01 10:00:01.0'
  • 列舉值或常量:Color.Tabby 

4.order by子句

按照任何返回的類或者元件的屬性排序:asc升序、desc降序。

public IList<Customer> Orderby()
{
    return _session.CreateQuery("from Customer c order by c.Firstname asc,c.Lastname desc")
        .List<Customer>();
}

5.group by子句

按照任何返回的類或者元件的屬性進行分組。

public IList<object[]> Groupby()
{
    return _session.CreateQuery("select c.Firstname, count(c.Firstname) from Customer c group by c.Firstname")
        .List<object[]>();
}

例項分析

好的,以上基本的查詢的確非常簡單,我們還是參考一下例項,分析一下我們如何寫HQL查詢吧!

例項1:按照FirstName查詢顧客:

public IList<Customer> GetCustomersByFirstname(string firstname)
{
    //寫法1
    //return _session.CreateQuery("from Customer c where c.Firstname='" + firstname + "'")
    //    .List<Customer>();

    //寫法2:位置型引數
    //return _session.CreateQuery("from Customer c where c.Firstname=?")
    //    .SetString(0, firstname)
    //    .List<Customer>();

    //寫法3:命名型引數(推薦)
    return _session.CreateQuery("from Customer c where c.Firstname=:fn")
        .SetString("fn", firstname)
        .List<Customer>();
}

書寫HQL引數有四種寫法:

  • 寫法1:可能會引起SQL注入,不要使用。
  • 寫法2:ADO.NET風格的?引數,NHibernate的引數從0開始計數。
  • 寫法3:命名引數用:name的形式在查詢字串中表示,這時IQuery介面把實際引數繫結到命名引數。
  • 寫法4:命名的引數列表,把一些引數新增到一個集合列表中的形式,比如可以查詢資料是否在這個集合列表中。

使用命名引數有一些好處:命名引數不依賴於它們在查詢字串中出現的順序;在同一個查詢中可以使用多次;它們的可讀性好。所以在書寫HQL使用引數的時候推薦命名型引數形式。

測試一下這個方法吧:看看資料庫中Firstname為“YJingLee”的記錄個數是否是1條,並可以判斷查詢出來的資料的FirstName屬性是不是“YJingLee”。

[Test]
public void GetCustomerByFirstnameTest()
{
    IList<Customer> customers = _queryHQL.GetCustomersByFirstname("YJingLee");
    Assert.AreEqual(1, customers.Count);
    foreach (var c in customers)
    {
        Assert.AreEqual("YJingLee", c.Firstname);
    }
}

例項2:獲取顧客ID大於CustomerId的顧客:

public IList<Customer> GetCustomersWithCustomerIdGreaterThan(int customerId)
{
    return _session.CreateQuery("from Customer c where c.CustomerId > :cid")
        .SetInt32("cid", customerId)
        .List<Customer>();
}

結語

在這篇文章中,我們瞭解了NHibernate其中的一種查詢語言HQL,這些例項我爭取寫出來可以執行起來,大家下載原始碼看看效果,一些資料需要按個人情況修改。例如查詢條件結果。下一節繼續介紹另外一種查詢語言!注意,這篇有的是返回IList<object[]>型別,在實際專案中不可能使用這個型別,我們需要使用一個物件,就是一個DTO轉換返回IList<ClassDTO>型別。