許多應用不需要一次查詢資料表所有資料。例如用戶管理系統需區分「活躍用戶」與「過期用戶」,狀態儲存在用戶表某欄位。傳統做法是在每條 HQL 追加 WHERE 條件,但這會修改大量既有代碼,風險高且難維護。Hibernate 3.x 提供的過濾器 (Filter) 可在映射檔預先定義條件,並在 Session 執行期動態啟用/停用、傳遞參數,實現零侵入式查詢限制。
缺點:運行時無法動態創建新過濾器,必須在映射檔預先定義。
在 <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>
enableFilter(String filterName):啟用並回傳 Filter 實例getEnabledFilter(String filterName):取得已啟用的 FilterdisableFilter(String filterName):停用過濾器預設過濾器關閉,需顯式啟用並設定參數:
session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");
雇員資料含 effectiveStartDate、effectiveEndDate,需查詢指定日期生效的記錄。
<filter-def name="effectiveDate">
<filter-param name="asOfDate" type="date"/>
</filter-def>
<class name="Employee">
<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.enableFilter("effectiveDate").setParameter("asOfDate", new Date());
List results = session.createQuery("from Employee e where e.salary > :targetSalary")
.setLong("targetSalary", 1000000L)
.list(); // 僅返回當前生效且薪資超過百萬的雇員
敏感實體 Opportunity 有 accessLevel 欄位,用戶只能看權限內的資料。
<filter-def name="accessLevel">
<filter-param name="userLevel" type="int"/>
</filter-def>
<class name="Opportunity">
<property name="accessLevel" type="int" column="access_lvl"/>
<filter name="accessLevel" condition="access_lvl <= :userLevel"/>
</class>
<class name="Region">
<set name="opportunities" lazy="true">
<key column="region_id"/>
<one-to-many class="Opportunity"/>
<filter name="accessLevel" condition="access_lvl <= :userLevel"/>
</set>
</class>
啟用過濾器:
User user = ...;
Session session = ...;
session.enableFilter("accessLevel").setParameter("userLevel", user.getAccessLevel());
Region region = (Region) session.get(Region.class, "EMEA");
int count = region.getOpportunities().size(); // 自動過濾至用戶權限內的機會
Hibernate 3.x 過濾器提供強大且靈活的查詢限制機制,透過映射檔集中定義、Session 動態控制,極大降低業務邏輯與查詢條件的耦合。結合攔截器、Web Filter 等技術,可構建更完善的資料存取控制體系。