A suggestion for org.jboss.seam.framework.Query
bobyang Oct 8, 2009 6:09 PMCould the Query class be added a new property for specifying the appending logical operator that concatenate the basic EJBQL string with the whole restriction properties?
The class EntityQuery is extended the class Query. When I use the EntityQuery like below:
@Name("worklogList") public class WorklogList extends EntityQuery<Worklog> { private static final long serialVersionUID = 5221868912115801552L; private static final String EJBQL = "select worklog from Worklog worklog "+ "where Worklog.executor.account.userName=#{authenticatedUser.userName}"; private static final String[] RESTRICTIONS = { "lower(worklog.work) like lower(concat(#{worklogList.worklog.work},'%'))", "lower(worklog.progress) like lower(concat(#{worklogList.worklog.progress},'%'))" }; private Worklog worklog = new Worklog(); public WorklogList() { setEjbql(EJBQL); setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS)); setMaxResults(25); setRestrictionLogicOperator("and"); } public Worklog getWorklog() { return worklog; } }
Notice that the EJBQL contains one where clause, the Query class will append restrictions to the EJBQL string with restrictionLogicOperator. So when user choose the 'or' logical operator from the XXXList.xhtml page, the final query string will become:
select worklog from Worklog worklog where Worklog.executor.account.userName=#{authenticatedUser.userName} or lower(worklog.work) like lower(concat(#{worklogList.worklog.work},'%')) or lower(worklog.progress) like lower(concat(#{worklogList.worklog.progress},'%'))
But most time we use the EJBQL string as the basic query condition, so the desired query string should like below, especially with the bracket enclosing the whole restriction strings :
select worklog from Worklog worklog where Worklog.executor.account.userName=#{authenticatedUser.userName} and ( lower(worklog.work) like lower(concat(#{worklogList.worklog.work},'%')) or lower(worklog.progress) like lower(concat(#{worklogList.worklog.progress},'%')) )
To achieve this query string, now I have to copy EntityQuery class to MyEntityQuery and make it extends MyQuery class.
The MyEntityQuery class is just the copy of EntityQuery but the MyQuery has little modification.
My modified Query class snippet is
public abstract class MyQuery<T, E> extends PersistenceController<T> { ...... private String restrictionAppendLogicOperator; ...... protected String getRenderedEjbql() { StringBuilder builder = new StringBuilder().append(parsedEjbql); boolean isAppendLogicOpAdded = false; for (int i=0; i<getRestrictions().size(); i++) { Object parameterValue = restrictionParameters.get(i).getValue(); if ( isRestrictionParameterSet(parameterValue) ) { if ( WHERE_PATTERN.matcher(builder).find() ) { // added by YangBo if(getRestrictionAppendLogicOperator()!=null && !isAppendLogicOpAdded) { sanitizeRestrictionLogicOperator(getRestrictionAppendLogicOperator()); builder.append(" ").append(getRestrictionAppendLogicOperator()).append(" ( "); isAppendLogicOpAdded = true; } else { builder.append(" ").append(getRestrictionLogicOperator()).append(" "); } } else { builder.append(" where "); } builder.append( parsedRestrictions.get(i) ); } } if ( isAppendLogicOpAdded ) { builder.append(" ) "); isAppendLogicOpAdded = false; } if (getGroupBy()!=null) { builder.append(" group by ").append(getGroupBy()); } if (getOrder()!=null) { builder.append(" order by ").append( getOrder() ); } return builder.toString(); } ...... }
By specify the new restrictionAppendLogicOperator property we can controll how the restriction strings be concatenate to the basic EJBQL without the side-effect of the restrictionLogicOperator.
In short the restrictionLogicOperator is responsible for the internal concatenation of restrictions strings while the new restrictionAppendLogicOperator is responsible for concatenation of basic EJBQL and the whole restrictions.
If this suggestion be accept, I'd like to make a patch for it.
Cheers!