Pages

Sunday, July 15, 2007

Filtering the result in hibernate

The filtering in hibernate can be acheived in two ways.
One, applying the filtering on the session before a finder or any query is hit.
Two, applying the filtering on the collection which is a persistent set after the query is hit.

For the first one,
An entry has to be made in the hbm xml's defing the filter, the parameters it take and the persistent collection on which the filter has to be applied to. Then before hitting the query on the session, we enable the filter on the session. Once the filter is enabled, any query on the session resulting in the persistent collection on which the filtering has been enable will be filtered on the filtering condition specified.

Example:

Example.hbm.xml
-------------------
<hibernate-mapping>
<class>
.
.
<set name="exampleTwo" inverse="true">
<key>
<column name="EXAMPLETWO_ID" precision="12" scale="0" />
</key>
<one-to-many class="ExampleTwo" />
<filter name="CaseOneFilter" condition="ACTIVE_IND = :CaseOneFilterParam"/>
</set>
</class>

<filter-def name="CaseOneFilter">
<filter-param name="CaseOneFilterParam" type="char"/>
</filter-def>

</hibernate-mapping>

In Code,
we enable the filter as:
session.enableFilter("CaseOneFilter").setParameter("CaseOneFilterParam",'Y');


For the second case,
Once we hit a finder and get a hook on a persistent object, we can create a filter on the session. The collection associated with this persistent object on which filtering has to be applied is sent to this newly created filter on the session. This results in getting a collection which is filtered on the conditions specified in the filter.

Example:


public static <T> Collection<T> filterCollection(Collection<T> collection, Session session,String filterCondition) {
Query filterQuery = s.createFilter(collection, filterCondition);
return filterQuery.list();
}

This can be called as:
/**
* Assuming pk to be perisitent object, session to be hibernate session.
*
*/
filterCollection(pk.getChildrens(), session, "select this.attribute where this.id = 23");

Eager fetching in Hibernate using Criteria queries

One of the easiest way of eager fetching is using the setFetchMode function present with Criteria API's. The whole clutter of reflection which i presented below can be removed by using this.
But the criteria queries when doing eager loading gives duplicate resultsets, what i mean is if the parent table has one row and the child table associated with it has say 2 rows then on doing an eager fetch we receive 2 parent Objects representing the parent table. This is because, eager fetching is nothing but putting 'sql join' on the underlying tables. And, as a result of this outer joins we get duplicate results. To get distinct results we have to use resultTransformer. The same code is given below.
.
.
Class Example{//Associated with Table EXAMPLE in Example.hbm.xml
private String attributeOne;
private ExampleTwo exampleTwo; //A foreign one to one relation with ExampleTwo
//Getters and Setters
}
.
Class ExampleTwo{//Associated with Table EXAMPLE_TWO in Example.hbm.xml
private String attributeOne;
//Getters and Setters
}
.
Criteria criteria = session.createCriteria(Example.class); //Create the criteria query
List fetchList=new ArrayList();
fetchList.add(exampleTwo);
initializeFetchList(Criteria criteria, List fetchList); //initialize
List exmpleList = criteria.list() //Executing this gives us List of Example Objects with pre-fetched ExampleTwo Objects in it.
.
.
public void initializeFetchList(Criteria criteria, List fetchList){

for (String entityAttribute : fetchList) {
criteria.setFetchMode(entityAttribute, FetchMode.JOIN);
}

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
}