Java中使用Hibernate系列之過濾器(filters)學習
Hibernate3新增了對某個類或者集合使用預先定義的過濾器條件(filter criteria)的功能。過濾器條件相當於定義一個 非常類似於類和各種集合上的“where”屬性的約束子句,但是過濾器條件可以帶引數。 應用程式可以在執行時決定是否啟用給定的過濾器,以及使用什麼樣的引數值。 過濾器的用法很像資料庫檢視,只不過是在應用程式中確定使用什麼樣的引數的。
網路配圖
要使用過濾器,必須首先在相應的對映節點中定義。而定義一個過濾器,要用到位於<hibernate-mapping/> 節點之內的<filter-def/>節點:
<filter-def name="myFilter"><filter-param name="myFilterParam" type="string"/></filter-def>
定義好之後,就可以在某個類中使用這個過濾器:
<class name="myClass" ...>...<filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/></class>
也可以在某個集合使用它:
<set ...><filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/></set>
可以在多個類或集合中使用某個過濾器;某個類或者集合中也可以使用多個過濾器。
Session物件中會用到的方法有:enableFilter(String filterName), getEnabledFilter(String filterName), 和 disableFilter(String filterName). Session中預設是不啟用過濾器的,必須通過Session.enabledFilter()方法顯式的啟用。 該方法返回被啟用的Filter的例項。以上文定義的過濾器為例:
session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");
注意,org.hibernate.Filter的方法允許鏈式方法呼叫。(類似上面例子中啟用Filter之後設定Filter引數這個“方法鏈”) Hibernate的其他部分也大多有這個特性。
下面是一個比較完整的例子,使用了記錄生效日期模式過濾有時效的資料:
<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"/>...<!--Note that this assumes non-terminal records have an eff_end_dt set toa max db date for simplicity-sake注意,為了簡單起見,此處假設僱用關係生效期尚未結束的記錄的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中,雖然我們僅僅顯式的使用了一個薪水條件,但因為啟用了過濾器,查詢將僅返回那些目前僱用 關係處於生效期的,並且薪水高於一百萬美刀的僱員的資料。
注意:如果你打算在使用外連線(或者通過HQL或load fetching)的同時使用過濾器,要注意條件表示式的方向(左還是右)。 最安全的方式是使用左外連線(left outer joining)。並且通常來說,先寫引數, 然後是操作符,最後寫資料庫欄位名。
在Filter定義之後,它可能被附加到多個實體和/或集合類,每個都有自己的條件。假若這些條件都是一樣的,每次都要定義就顯得很繁瑣。因此,<filter-def/>被用來定義一個預設條件,它可能作為屬性或者CDATA出現:
<filter-def name="myFilter" condition="abc > xyz">...</filter-def><filter-def name="myOtherFilter">abc=xyz</filter-def>
當這個filter被附加到任何目的地,而又沒有指明條件時,這個條件就會被使用。注意,換句話說,你可以通過給filter附加特別的條件來過載預設條件。