在很多應用程序中不需要一次使用數據表中的所有的數據。在這種情況下,我們就需要使用Hibernate的過濾器(Filter)來得到一個數據字集。過濾器的主要作用是限制我們的應用程序的查詢數據。這個過濾器的概念并不是什么新概念,如數據庫的視圖也屬于過濾器范疇。而Hibernate為我們提供的過濾器是在一個抽象的層次,它可以做到和不依賴于數據庫的類型,使數據訪問層只面對一個解決方案,那就是Hibernate Filter。當然,直接在數據庫中建立視圖也算一種解決方案,但這樣做太不靈活。而Hibernate過濾器卻能夠在Hibernate會話的過程中打開或關閉。另外,另外,Hibernate過濾器可以傳遞參數,這樣將大大增加Hibernate的靈活性。雖然Hibernate2也提供了過濾器,但Hibernate3.x提供了一種全新的過濾器。
Hibernate3的過濾器可以進行預定義,并可綁定在類和集合層。那么什么叫預定義過濾器呢?就是可以定義象"where"子句的限制性子句,但這些子句是相對類和不同集合的元素的。除了這些過濾器條件可以被參數化外。系統還能決定在運行是指定的過濾器是否應該被打開以及什么值被傳入過濾器參數。
一、什么時候使用過濾器
為了解釋為什么使用過濾器,下面讓我們先來看一個例子。假設有一個管理用戶信息的Web應用程序。在當前狀態,我們的應用程序使用同一個應用接口來處理所有的用戶信息。但如果最終用戶要求將活動用戶和過期用戶分開管理。這些狀態信息被保存在用戶表的某一列中。對于這種需求,我們最容易想到的一個解決方案是重新寫每一個SELECT HQL查詢語句,也就是在每一個HQL后加一個WHERE條件來過濾這些數據。當然,這種方法的復雜程序取決于你的Web程序是如何建立的,可以很簡單,也可以很復雜。但不管是簡單還是復雜,都必須得修改我們曾經測試過的代碼,這將給我們的程序帶來非常大的隱患。而使用Hibernate3.x,將會給我們帶來另外一個解決方案。我們將會為應用程序的用戶狀態創建一個過濾器。當用戶選擇用戶的狀態時(活動或過期),應用程序將激活當前Hibernate會話的用戶狀態過濾器。這樣以來,所有的SELECT HQL查詢將返回查詢結果的子集,而我們只需要在Hibernate會話狀態和用戶狀態過濾器兩個地方添加代碼,并不需要修改原先的代碼。
從概念上講,你可以使用WHERE子句在應用程序中完成和Hibernate過濾器同樣的工作。當然,我們還可以在數據庫中建立視圖來完成同樣的工作(但所使用的數據庫必須支持視圖功能)。這三種解決方案都可以通過一個或多個查詢條件來限制最終結果。而Hibernate過濾器的優勢就在于可以隨時在程序中關閉或打開,也就是說過濾器是可編程的,而且過濾器被定義在Hibernate的映射文件中,這樣將非常容易維護。當然,過濾器也有不足的地方,主要的不足就是在運行時無法創建新的過濾器。而程序在運行時,所有的過濾器必須要在映射文件中被指定。雖然這將大大限制過濾器的靈活性,但過濾器支持參數化。對于本文的例子,我們可以在映射文件中指定保存用戶狀態信息的列。我們不需要在映射文件中指定可能的狀態值,這些在程序運行時都可以指定。接下來我們就來看看如何使用Hibernate3.x中的過濾器來寫程序。
在很多應用程序中不需要一次使用數據表中的所有的數據。在這種情況下,我們就需要使用Hibernate的過濾器(Filter)來得到一個數據字集。過濾器的主要作用是限制我們的應用程序的查詢數據。這個過濾器的概念并不是什么新概念,如數據庫的視圖也屬于過濾器范疇。而Hibernate為我們提供的過濾器是在一個抽象的層次,它可以做到和不依賴于數據庫的類型,使數據訪問層只面對一個解決方案,那就是Hibernate Filter。當然,直接在數據庫中建立視圖也算一種解決方案,但這樣做太不靈活。而Hibernate過濾器卻能夠在Hibernate會話的過程中打開或關閉。另外,另外,Hibernate過濾器可以傳遞參數,這樣將大大增加Hibernate的靈活性。雖然Hibernate2也提供了過濾器,但Hibernate3.x提供了一種全新的過濾器。
Hibernate3的過濾器可以進行預定義,并可綁定在類和集合層。那么什么叫預定義過濾器呢?就是可以定義象"where"子句的限制性子句,但這些子句是相對類和不同集合的元素的。除了這些過濾器條件可以被參數化外。系統還能決定在運行是指定的過濾器是否應該被打開以及什么值被傳入過濾器參數。
一、什么時候使用過濾器
為了解釋為什么使用過濾器,下面讓我們先來看一個例子。假設有一個管理用戶信息的Web應用程序。在當前狀態,我們的應用程序使用同一個應用接口來處理所有的用戶信息。但如果最終用戶要求將活動用戶和過期用戶分開管理。這些狀態信息被保存在用戶表的某一列中。對于這種需求,我們最容易想到的一個解決方案是重新寫每一個SELECT HQL查詢語句,也就是在每一個HQL后加一個WHERE條件來過濾這些數據。當然,這種方法的復雜程序取決于你的Web程序是如何建立的,可以很簡單,也可以很復雜。但不管是簡單還是復雜,都必須得修改我們曾經測試過的代碼,這將給我們的程序帶來非常大的隱患。而使用Hibernate3.x,將會給我們帶來另外一個解決方案。我們將會為應用程序的用戶狀態創建一個過濾器。當用戶選擇用戶的狀態時(活動或過期),應用程序將激活當前Hibernate會話的用戶狀態過濾器。這樣以來,所有的SELECT HQL查詢將返回查詢結果的子集,而我們只需要在Hibernate會話狀態和用戶狀態過濾器兩個地方添加代碼,并不需要修改原先的代碼。
從概念上講,你可以使用WHERE子句在應用程序中完成和Hibernate過濾器同樣的工作。當然,我們還可以在數據庫中建立視圖來完成同樣的工作(但所使用的數據庫必須支持視圖功能)。這三種解決方案都可以通過一個或多個查詢條件來限制最終結果。而Hibernate過濾器的優勢就在于可以隨時在程序中關閉或打開,也就是說過濾器是可編程的,而且過濾器被定義在Hibernate的映射文件中,這樣將非常容易維護。當然,過濾器也有不足的地方,主要的不足就是在運行時無法創建新的過濾器。而程序在運行時,所有的過濾器必須要在映射文件中被指定。雖然這將大大限制過濾器的靈活性,但過濾器支持參數化。對于本文的例子,我們可以在映射文件中指定保存用戶狀態信息的列。我們不需要在映射文件中指定可能的狀態值,這些在程序運行時都可以指定。接下來我們就來看看如何使用Hibernate3.x中的過濾器來寫程序。
四、實例
1. 一個過濾數據的例子
現在假設有一個實體,這個實體跟著“有效的記錄”數據庫模式。這個實體有多個行,每一行都根據日期不同而不同,也就是說在日期范圍內是有效的。一個employment記錄將是一個非常好的例子,因為employees可以來或去或再回來。現在我們開發一個帶UI的程序,這個程序需要處理employment數據的當前記錄。為了使用新的過濾器特性達到這個目的。我們首先需要定義這個過濾器,然后將它附著在Employee類上。
<filter-def name="effectiveDate">
<filter-param name="asOfDate" type="date"/>
</filter-def>
<class name="Employee" ...>
...
<many-to-one name="department" column="dept_id" class="Department"/>
<property name="effectiveStartDate" type="date" column="eff_start_dt"/>
<property name="effectiveEndDate" type="date" column="eff_end_dt"/>
...
<filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
</class>
<class name="Department" ...>
...
<set name="employees" lazy="true">
<key column="dept_id"/>
<one-to-many class="Employee"/>
<filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
</set>
</class> |
然后,為了保證總是加在到當前的有效記錄。只要簡單地將過濾器打開即可,代碼如下:
Session session = ...;
session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
.setLong("targetSalary", new Long(1000000))
.list(); |
在上面的HQL中,即使我們只給出一個salary約束條件,由于我們已經打開發過濾器,也只會得到當前活動的比一百萬多的雇員。
2. 安全的實例
假設我們有一個應用程序,這個程序給每一個用戶分配一個訪問權限。在這其間,系統中一些敏感的實體被分配給了某些訪問層次。因此,一個用戶在它所屬的訪問層中應該可以看到更多的東西。在本例子中我們就要通過過濾器來過濾某一個訪問層次中的實體。下面讓我們來定義過濾器。
<filter-def name="accessLevel">
<filter-param name="userLevel" type="int"/>
</filter-def>
<class name="Opportunity" ...>
...
<many-to-one name="region" column="region_id" class="Region"/>
<property name="amount" type="Money">
<column name="amt"/>
<cloumn name="currency"/>
</property>
<property name="accessLevel" type="int" column="access_lvl"/>
...
<filter name="accessLevel">= access_lvl]]>
</class>
<class name="Region" ...>
...
<set name="opportunities" lazy="true">
<key column="region_id"/>
<one-to-many class="Opportunity"/>
<filter name="accessLevel">= access_lvl]]>
</set>
...
</class> |
接下來,讓我們來打開過濾器。
User user = ...;
Session session = ...;
session.enableFilter("accessLevel").setParameter("userLevel", user.getAccessLevel()); |
下面的代碼是一個正在裝載的區域,它將過濾當前用戶訪問層的集合以得到一個子集。
Region region = (Region) session.get(Region.class, "EMEA");
region.getOpportunities().size(); |
四、結論
本文簡單介紹了Hibernate3.x的使用方法,并給出了一些實例。雖然這些例子很簡單,但卻使我們對Hibernate3.x過濾器的強大有了更深的認識。我們通過上面的例子也許會有更多好的想法,如果能將它們和不同的攔截方法,如Web過濾器結合,將會發揮出更大的力量。(轉)
posted on 2009-03-02 17:58
ID刀 閱讀(172)
評論(0) 編輯 收藏 所屬分類:
Hibernate