hql介紹

 

一個ORM框架是建立在面向對象的基礎上的。最好的例子是Hibernate如何提供類SQL查詢。雖然HQL的語法類似於SQL,但實際上它的查詢目標是對象。HQL擁有面嚮對象語言的所有的特性,這其中包括多態、繼承和組合。這就相當於一個面向對象的SQL,爲了提供更強大的功能,HQL還提供了很多的查詢函數。這些函數可以被分爲四類:

  1. 投影函數

  2. 約束函數

  3. 聚合函數

  4. 分組函數

  使用HQL可以建立簡單的查詢,也可以建立更復雜的查詢。在本文中並不討論那些非常複雜的查詢,如含有子查詢和很多連接的查詢。本文只討論連接兩個表的查詢。現在讓我們開始接近HQL吧!

  投影

  如謂投影,就是一個可以訪問的對象或對象的屬性。在HQL中,可以使用from和select子句來完成這個工作。

  from子句返回指定的類的所有實例。如from Order將返回Order類的所有實例。換句話說,以上的查詢相當於以下的SQL語句:

select * from order

  from 是最簡單的查詢子句。from後面可以跟一個或多個類名(類名也可以帶有別名)。爲了得到Order和Product的所有實例,可以使用如下的查詢:

from Order, Product

  和類名一樣,別名也可以在from後使用,如下代碼如示:

from Order as o, Product p

  當查詢很複雜時,加入別名可以減少語句的長度。我們可以看看如下的SQL語句:

select o.*, p.* from order o, product p where o.order_id = p.order_id

  我們可以很容易看出,上面的查詢是一對多的關係。在HQL中相當於一個類中包含多個其它類的實例。因此,以上的SQL寫成HQL就是:

from Order as o inner join o.products as product

  現在讓我們考慮另外一個從表中得到指定屬性的情況。這就是最常用的select子句。這在HQL中的工作方式和SQL中一樣。而在HQL中,如果只是想得到類的屬性的話,select語句是最後的選擇。以上的SQL可以使用select子句改成如下的HQL語句:

select product from Order as o inner join o.products as product

  以上的HQL語句將返回Order中的所有Products實例。如果要得到對象的某一個屬性,可以將HQL語句寫成如下的形式:

select product.name from Order as o inner join o.products as product

  如果要得到多個對象的屬性,可以將HQL語句寫成如下形式:

select o.id, product.name from Order as o inner join o.products as product


  接下來,我們將進入下一個議題。假設我們需要根據某些條件得到數據。那麼以上所述的HQL語句將無法滿足需求。爲了達到這一目的,我們就要用到下面將要討論的約束子句。

約束

  從以上可知,投影返回的是所有的數據。但在大多數時候我們並不需要這麼多數據。這就需要對數據進行過濾。在HQL中過濾數據的子句和SQL一樣,也是where。它的語法類似於SQL,通過where子句,可以對行進行過濾。我們可以看看下面的SQL語句:

select * from orders where id = ‘1234’

  這條查詢語句返回了id等於1234的所有的字段。和這條SQL對等的是下面的HQL語句:

select o from Order o where o.id=’1234’

  從以上兩條語句可以看出,它們的where子句非常相似。而它們唯一的不同是SQL操作的是記錄,而HQL操作的是對象。在HQL中,除了where子句可以過濾數據外,having子句也可以做到這一點(關於having子句的詳細內容我將在分組部分討論)。投影和約束是兩個基本的操作,這兩個操作再加上聚合函數的話,那HQL將變得更加強大。下面我們就來討論什麼是聚合。

  聚合

  上述的查詢都是將每一個記錄(對象)當做一個單位,而如果使用聚合,可以將一類記錄(對象)當做一個單位。然後再對每一類的記錄(對象)進行一系列地操作,如對某一列取平均值、求和、統計行數等等。HQL支持以下的聚合函數:

  1. avg(…), sum(…)
  2. min(…), max(…)
  3. count(*), count(…), count(distinct…), count(all…)

  以上的聚合函數都返回數值類型。這些操作都可以在select子句中使用,如下所示:

select max(o.priceTotal) + max(p.price) from Order o join o.products p group by o.id

  以上的HQL語句返回了兩個值的和:orders表中的priceTotal的最大值和products表中的price的最大值之和。我們還可以使用having子句對分組進行過濾。如我們想按id統計priceTotal小於1000的數量可按如下的HQL語句去實現:

select count(o) from Order o having o.priceTotal < 1000 group by o.id

  我們還可以將聚合函數和having子句一起使用。如我們要按products表的id統計price小於amount的平均數的產品數量,HQL語句如下:

select count(p) from Product p having p.price < avg(amount) group by p.id

  從上面的一系列的HQL語句可以看出,所有通過SQL實現的,都可以通過HQL來實現。

  分組

  在上一部分,已經涉及到了分組的概念。分組操作的是行的集合。它根據某一列(屬性)對記錄集進行分組。這一切是通過group子句實現的。如下的例子描述了group子句的一般用法。

select count(o) from Order o having o.priceTotal >= 1200 and o.priceTotal <= 3200 group by o.id

  HQL中的分組和SQL中的分組類似。總之,除了一些對SQL的特殊擴展外,其它所有的SQL功能都可以使用HQL描述。在接下來的部分,讓我們舉例說明如何在java中使用HQL。

在java中使用HQL

  到現在爲止,我們已經學習了HQL的基本用法。接下來我們舉一個例子來說明如何在Java中使用HQL。下面的例子只給出了主要的部分,由於本文只是討論HQL的用法,因此,關於Hibernate的一些設置和在main()函數中調用Hibernate的部分並未給出,讀者可以參考相關的文當。現在讓我們看看下面的例子。

  下面是必須引用的包
 
import java.util.List;
import org.hibernate.*;
import org.hibernate.cfg.*
import com.Order;

  下面是類的聲明

public class MyOrder
{
… …
}

  下面讓我們來實現MyOrder類的構造函數

public class MyOrder
{
SessionFactory sf;

public MyOrder()
{
Configuration cfg = new Configuration().addClass(Order.class);
sf = cfg.buildSessionFactory();
}
… …
}

  下面的getOrder函數根據priceTotal的區間值返回Order對象。

public class MyOrder
{
…. ….
public Order getOrder(String lower, String upper)
{
// 打開一個會話
Session sess = sf.openSession();
// HQL語句
String query = "select o from o "
+ "Order as o join o.products as p "
+ "where o.priceTotal > :priceTotalLower"
+ "and o.priceTotal< :priceTotalUpper";

Query q = sess.createQuery(query);
// 將兩個參數傳入HQL中
q.setDouble("priceTotalLower", Double.parseDouble(lower));
q.setDouble("priceTotalUpper", Double.parseDouble(upper));

List list = q.list();

Order o=(Order)list.iterator.next();

return o;

}
… …
}

  下面的main函數將測試MyOrder類

public class MyOrder
{
… …
public static void main(String args[])
{
Order o=MyOrder().getOrder(“100”, “300”);
System.out.println(“id=”+ o.id);
… …
}
}

  小結

  上述的代碼演示瞭如何在Java中使用HQL,但HQL還有兩點需要注意一下:

  1. HQL並不區分字母的大小寫,但在HQL中的Java類和屬性名必須和實際的類和屬性名一致。如SELECT和select之間可以互換,但Order和order卻代表不同的含義。

  2. 如果HQL中引用的類未被導入,在HQL中必須引用具體的包。如本例中,如果com.Order未被導入,在HQL中必須將Order寫成com.Order。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章