Hibernate Hopes
I've been working with Hibernate's newCriteria interface for the past few days, and since it's not working as I hoped - I thought I'd detail my thoughts. The following code allows me to use one search parameter (wrapped with % signs) and find all matching columns with this value. This allows for a very simple UI where I have a single search box on a list screen that allows for filtering the displayed items. Here's an example:
boolean msoFilter = (msoIds.contains(new Long(-1))) ? false : true; boolean headendFilter = (headendIds.contains(new Long(-1))) ? false : true; List crList = null; String filter = "%" + filterBy + "%"; // Set query criteria - if a search term is passed in try { StringBuffer query = new StringBuffer(); query.append("from cr in class " + ChangeRequestDetail.class); if (headendFilter) { query.append(" where cr.headendId in (:headends)"); } else if (msoFilter) { query.append(" where cr.msoId in (:msos)"); } if (!StringUtils.isEmpty(filterBy)) { if (log.isDebugEnabled()) { log.debug("filtering on search term: " + filterBy.toLowerCase()); } if (headendFilter || msoFilter) { query.append(" and "); } else { query.append(" where "); } query.append(" ((cr.crId like :searchTerm)"); query.append(" or (lower(cr.stateDesc) like :searchTerm)"); query.append(" or (lower(cr.headendName) like :searchTerm)"); query.append(" or (cr.headendId like :searchTerm)"); query.append(" or (lower(cr.desiredCompleteDate) like :searchTerm)"); query.append(" or (lower(cr.effectiveDate) like :searchTerm)"); query.append(" or (lower(cr.requestorName) like :searchTerm))"); } query.append(" order by cr.desiredCompleteDate desc"); Query q = ses.createQuery(query.toString()); // Bind on headends OR msos if (headendFilter) { q.setParameterList("headends", headendIds); } else if (msoFilter) { q.setParameterList("msos", msoIds); } if (!StringUtils.isEmpty(filterBy)) { q.setParameter("searchTerm", filter.toLowerCase()); } crList = q.list(); ...
With the new Query by Criteria feature, this should be much easier, and I'd love if it was as simple as the following:
boolean msoFilter = (msoIds.contains(new Long(-1))) ? false : true; boolean headendFilter = (headendIds.contains(new Long(-1))) ? false : true; List crList = null; String filter = "%" + filterBy + "%"; // Set query criteria - if a search term is passed in try { Criteria criteria = ses.createCriteria(ChangeRequestDetail.class); if (headendFilter) { criteria.add(Expression.in("headendId", headendIds)); } else if (msoFilter) { criteria.add(Expression.in("msoId", msoIds)); } if (!StringUtils.isEmpty(filterBy)) { if (log.isDebugEnabled()) { log.debug("filtering on search term: " + filterBy.toLowerCase()); } String[] properties = {"crId", "stateDesc", "headendName", "headendId", "desiredCompleteDate", "effectiveDate", "requestorName"}; criteria.add(Expression.anyILike(properties, filter)); } criteria.addOrder(Order.desc("desiredCompleteDate")); crList = criteria.list(); ...
To make this possible, I propose the following methods be added to the Expression class in Hibernate. NOTE: I've added these methods and things don't work as I'd hoped. You can follow my progress on getting this implemented (or not) on Hibernate's SourceForge Forum.
/** * Apply an "ilike" constraint to any property in the * key set of a Map * * @param propertyNameValues a map from property names to values * @return Expression */ public static Expression anyILike(Map propertyNameValues) { Disjunction disj = disjunction(); Iterator iter = propertyNameValues.entrySet().iterator(); while ( iter.hasNext() ) { Map.Entry me = (Map.Entry) iter.next(); disj.add( ilike( (String) me.getKey(), me.getValue() ) ); } return disj; } /** * Apply an "ilike" constraint to all properties based on a single value. * * @param propertyNames * @param value * @return Expression */ public static Expression anyILike(String[] propertyNames, String value) { Disjunction disj = disjunction(); for (int i=0; i < propertyNames.length; i++) { disj.add( ilike ( propertyNames[i], value)); } return disj; } /** * Apply a "like" constraint to any property in the * key set of a Map * * @param propertyNameValues a map from property names to values * @return Expression */ public static Expression anyLike(Map propertyNameValues) { Disjunction disj = disjunction(); Iterator iter = propertyNameValues.entrySet().iterator(); while ( iter.hasNext() ) { Map.Entry me = (Map.Entry) iter.next(); disj.add( like( (String) me.getKey(), me.getValue() ); } return disj; }