使用Hibernate的级联查询时(以one-to-many为例),当查询主表对象并想同时级联查询关联的从表对象时,往往会将该主表ID关联的所有从表数据都取出来,有些时候我们希望在主表关联从表的时候能用额外的条件对从表数据加以过滤,使其只查询我们想要的那部分结果集。
本文主要是在one-to-many级联关系中使用Filter过滤子类的Set集合,使得在父类级联查询子类对象时,只查询满足条件的子类对象。
环境:spring+hibernate 3.2,由于spring不暴露Hibernate的session对象,因此这里要是用Hibernate原生对象要用到Template的回调函数。
主表:CsDailyReport
id | CHAR(32) | 主键 | ID |
reporter | varchar2(100) | 填报人 | |
reportDate | date | 填报日期 | |
unitId | char(32) | 所属单位 | |
note | varchar2(255) | 备注 |
从表:CsDailyReportDetail
id | char(32) | 主键 | ID |
reporter_id | char(32) | 日报ID | |
area_id | char(32) | 区域ID | |
problem | varchar2(4000) | 问题 |
由以上表结构,我们想在查询CsDailyReport的时候,同时级联产出area_id为给定数值的CsDailyReportDetail数据。
Hibernate配置文件如下:
CsDailyReport.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="CsDailyReport" table="CS_DAILYREPORT"> <!-- 映射ID --> <id name="id" column="id" type="string" unsaved-value="null"> <generator class="uuid.hex"/> </id> <!-- 映射属性 --> <property name="reporter" column="REPORTER" type="string"/> <property name="reportDate" column="REPORT_DATE" type="date"/> <property name="problem" column="PROBLEM" type="string"/> <!-- 级联映射 --> <!-- <many-to-one name="unit" column="GASUNITID" class="Unit"/> --> <set name="details" inverse="true" cascade="delete" lazy="false"> <key column="REPORT_ID"/> <one-to-many class="CsDailyReportDetail"/> <!--设置Filter--> <filter name="detailAreaFilter" condition="AREA_ID=:areaId"/> </set> </class> <!--Filter声明--> <filter-def name="detailAreaFilter"> <filter-param name="areaId" type="string"/> </filter-def> </hibernate-mapping>
CsDailyReportDetail.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="CsDailyReportDetail" table="CS_DAILYREPORT_DETAILS"> <!-- 映射ID --> <id name="id" column="id" type="string" unsaved-value="null"> <generator class="uuid.hex"/> </id> <!-- 映射属性 --> <property name="problem" column="PROBLEM" type="string"/> <!-- 级联映射 --> <many-to-one name="report" column="REPORT_ID" class="CsDailyReport"/> </class> </hibernate-mapping>
声明Filter:
<filter-def name="detailAreaFilter"> <filter-param name="areaId" type="string"/> </filter-def>
<set name="details" inverse="true" cascade="delete" lazy="false"> <key column="REPORT_ID"/> <one-to-many class="CsDailyReportDetail"/> <!--设置Filter--> <filter name="detailAreaFilter" condition="AREA_ID=:areaId"/> </set>
是关联从表集合。其中"name"为"detailAreaFilter"的Filter(也就是上面声明的那个Filter);"condition"是指定过滤条件为"AREA_ID"等于Filter参数代替的值(其中"AREA_ID"是上面CsDailyReportDetail的一个字段)。
在测试类中添加如下方法:
public List<CsDailyReport> findReports(final String areaId) throws Exception { final StringBuffer queryString = new StringBuffer("from CsDailyReport as entity"); return (List<CsDailyReport>) getHibernateTemplate().executeFind( new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { //开启Filter session.enableFilter("detailAreaFilter").setParameter("areaId", areaId); Query query = session.createQuery(queryString.toString()); return query.list(); } } ); }
在Hibernate3中可以方便的设置Filter是否开启。