Share my implementation of EntityQuery by Entity Example, an
zjsun Jan 16, 2008 10:12 PMStructure:
EntityQuery
ExampleEntityQuery + EntityQueryState
RestrictedExampleEntityQuery
Note:
ExampleEntityQuery used to generate dynamic ejbql at runtime according to the entity class and entity instance ...
EntityQueryState used to hold query state, include orderby info, page info, example entity...
RestrictedExampleEntityQuery used to control user permission on this query, by adding more restriction "where" ejbql
public abstract class ExampleEntityQuery<E> extends EntityQuery { private static final long serialVersionUID = 4830838552107053677L; public static final Pattern FROM_PATTERN = Pattern.compile( "(^|\\s)(from)\\s", Pattern.CASE_INSENSITIVE); public static final Pattern ORDER_CLAUSE_PATTERN = Pattern .compile("^[\\w\\.,\\s]*$"); public static final Pattern ORDER_PATTERN = Pattern.compile( "\\s(order)(\\s)+by\\s", Pattern.CASE_INSENSITIVE); public static final Pattern WHERE_PATTERN = Pattern.compile( "\\s(where)\\s", Pattern.CASE_INSENSITIVE); @Logger private Log log; // private EntityQueryState<E> state; public abstract void setState(EntityQueryState<E> state); public abstract EntityQueryState<E> getState(); protected String buildCountEjbql() { // return super.getCountEjbql(); String ejbql = getRenderedEjbql(); boolean distincted = ejbql.startsWith("select distinct"); Matcher fromMatcher = FROM_PATTERN.matcher(ejbql); if (!fromMatcher.find()) { throw new IllegalArgumentException("no from clause found in query"); } int fromLoc = fromMatcher.start(2); Matcher orderMatcher = ORDER_PATTERN.matcher(ejbql); int orderLoc = orderMatcher.find() ? orderMatcher.start(1) : ejbql .length(); String countQl = "select count(*) "; if (distincted) { Class entityClass = ReflectionsUtils.getClassParameterType( getClass(), 0); // String entityClassName = entityClass.getSimpleName(); String entityAliasName = EntityUtils .getEntityAliasName(entityClass); countQl = "select count(distinct " + entityAliasName + ") "; } countQl += ejbql.substring(fromLoc, orderLoc); logQl("Seam ext (Query countEjbql) : " + countQl); return countQl; } protected String buildEjbql() { Class entityClass = ReflectionsUtils.getClassParameterType(getClass(), 0); String entityClassName = entityClass.getSimpleName(); String entityAliasName = EntityUtils.getEntityAliasName(entityClass); StringBuffer joinBuilder = new StringBuffer(); StringBuffer whereBuilder = new StringBuffer(); boolean joined = false; if (getState() != null) { if (getState().getExample() != null) { for (PropertyDescriptor pd : PropertyUtils .getPropertyDescriptors(entityClass)) { if (ReflectionsUtils.isInstanceOf(pd.getPropertyType(), Collection.class.getName())) { Field field = ReflectionsUtils.getField(entityClass, pd .getName()); Method fieldGetterMethod = ReflectionsUtils .getGetterMethod(entityClass, pd.getName()); Collection fieldValue = null; try { fieldValue = (Collection) fieldGetterMethod.invoke( getState().getExample(), new Object[] {}); } catch (Exception e) { e.printStackTrace(); } if (fieldValue != null && fieldValue.size() > 0) { Class propertyEntityClass = ReflectionsUtils .getCollectionElementType(field .getGenericType()); String propertyAliasName = EntityUtils .getEntityAliasName(propertyEntityClass); joinBuilder.append(" left join " + entityAliasName + "." + pd.getName() + " " + propertyAliasName); joined = true; } } } } // 如果是针对当å‰�entity的一个property说对应的entity进行查询 if (getState().getQueryPropertyName() != null) { Field field = ReflectionsUtils.getField(entityClass, getState() .getQueryPropertyName()); boolean bCollectionType = ReflectionsUtils.isInstanceOf(field .getType(), Collection.class.getName()); Class propertyEntityClass = field.getType(); if (bCollectionType) { propertyEntityClass = ReflectionsUtils .getCollectionElementType(field.getGenericType()); } String propertyAliasName = EntityUtils .getEntityAliasName(propertyEntityClass); String joinItem = " join " + entityAliasName + "." + field.getName() + " " + propertyAliasName; // TODO:暂时使用粗糙的检测是å�¦å˜åœ¨ if (joinBuilder.toString().indexOf(joinItem) == -1) { if (bCollectionType) { joinBuilder.append(" left").append(joinItem); } else { joinBuilder.append(joinItem); } whereBuilder.append(propertyAliasName + " is not null"); joined = true; } } } StringBuffer selectBuilder = new StringBuffer(); if (joined) { selectBuilder.append("select distinct "); } else { selectBuilder.append("select "); } if (getState() != null && getState().getQueryPropertyName() != null) { Field field = ReflectionsUtils.getField(entityClass, getState() .getQueryPropertyName()); boolean bCollectionType = ReflectionsUtils.isInstanceOf(field .getType(), Collection.class.getName()); Class propertyEntityClass = field.getType(); if (bCollectionType) { propertyEntityClass = ReflectionsUtils .getCollectionElementType(field.getGenericType()); } String propertyAliasName = EntityUtils .getEntityAliasName(propertyEntityClass); selectBuilder.append(propertyAliasName); } else { selectBuilder.append(entityAliasName); } selectBuilder.append(" from ").append(entityClassName).append(" ") .append(entityAliasName).append(joinBuilder); if (whereBuilder.length() > 0) { selectBuilder.append(" where ").append(whereBuilder); } logQl("Seam ext (Query ejbql) : " + selectBuilder.toString()); return selectBuilder.toString(); } protected List<QueryJoin> buildJoins() { List<QueryJoin> joins = new ArrayList<QueryJoin>(); return joins; } protected List<String> buildRestrictions() { List<String> restrictions = new ArrayList<String>(); if (getState() != null && getState().getExample() != null) { Class entityClass = ReflectionsUtils.getClassParameterType( getClass(), 0); // String entityClassName = entityClass.getSimpleName(); String entityAliasName = EntityUtils .getEntityAliasName(entityClass); String queryComponentName = Seam.getComponentName(getClass()); for (PropertyDescriptor pd : PropertyUtils .getPropertyDescriptors(entityClass)) { if (!ReflectionsUtils.isInstanceOf(pd.getPropertyType(), Class.class.getName())) { if (ReflectionsUtils.isInstanceOf(pd.getPropertyType(), String.class.getName())) { // 如果String类型,则使用 like 查询 restrictions.add("lower(" + entityAliasName + "." + pd.getName() + ") like " + "lower('%'||#{" + queryComponentName + ".state.example." + pd.getName() + "}||'%')"); } else if (ReflectionsUtils.isInstanceOf(pd .getPropertyType(), Collection.class.getName())) { // 如果是Collection,则é…�å�ˆå‰�é�¢çš„left join 使用inå�查询方å¼� Field field = ReflectionsUtils.getField(entityClass, pd .getName()); Method fieldGetterMethod = ReflectionsUtils .getGetterMethod(entityClass, pd.getName()); Collection fieldValue = null; try { fieldValue = (Collection) fieldGetterMethod.invoke( getState().getExample(), new Object[] {}); } catch (Exception e) { e.printStackTrace(); } if (fieldValue != null && fieldValue.size() > 0) { Class propertyEntityClass = ReflectionsUtils .getCollectionElementType(field .getGenericType()); String propertyAliasName = EntityUtils .getEntityAliasName(propertyEntityClass); restrictions.add(propertyAliasName + " in (select " + propertyAliasName + "_ from " + propertyEntityClass.getSimpleName() + " " + propertyAliasName + "_ where " + propertyAliasName + "_ in (#{" + queryComponentName + ".state.example." + pd.getName() + "}))"); } } else { // 其余直接进行 = 查询 restrictions.add(entityAliasName + "." + pd.getName() + " = " + "#{" + queryComponentName + ".state.example." + pd.getName() + "}"); } } } } return restrictions; } @Override public void validate() { super.validate(); if (getState() == null) { // throw new IllegalStateException("state is null"); } } @Override protected String getRenderedEjbql() { String ql = super.getRenderedEjbql(); logQl("Seam ext (Query renderedEjbql) : " + ql); return ql; } @Override protected String getCountEjbql() { return buildCountEjbql(); } @Override public Integer getFirstResult() { return getState() == null ? super.getFirstResult() : getState() .getCurrentPage(); } @Override public Integer getMaxResults() { return getState() == null ? super.getMaxResults() : getState() .getPageSize(); } @Override public String getOrder() { return getState() == null ? super.getOrder() : getState().getOrderBy(); } @Override protected boolean isRestrictionParameterSet(Object parameterValue) { boolean bSet = super.isRestrictionParameterSet(parameterValue); if (bSet) { if (parameterValue != null && parameterValue instanceof Collection) { bSet = ((Collection) parameterValue).size() > 0; } } return bSet; } @Override public String getEjbql() { return buildEjbql(); } @Override public List<String> getRestrictions() { return buildRestrictions(); } public void refreshQuery() { // clear the parsed QL setEjbql(null); setRestrictions(null); super.refresh(); } private void logQl(String ql) { log.info(ql); } }
public class EntityQueryState<E> implements Serializable { private static final long serialVersionUID = 4999435737345385599L; private E example; private Integer pageSize; private Integer currentPage; private String orderBy; // ç”¨äºŽæ ‡è¯†æ˜¯å�¦æŸ¥è¯¢å½“å‰�Entityçš„æŸ�个property(Entity类型)的List private String queryPropertyName; // TODO:how to implement? private List<QueryJoin> queryJoins = new ArrayList<QueryJoin>(); public E getExample() { return example; } public void setExample(E entity) { this.example = entity; } public String getOrderBy() { return orderBy; } public void setOrderBy(String orderby) { this.orderBy = orderby; } public Integer getPageSize() { return pageSize; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } public Integer getCurrentPage() { return currentPage; } public void setCurrentPage(Integer currentPage) { this.currentPage = currentPage; } public String getQueryPropertyName() { return queryPropertyName; } public void setQueryPropertyName(String propertyName) { this.queryPropertyName = propertyName; } public List<QueryJoin> getQueryJoins() { return queryJoins; } public void setQueryJoins(List<QueryJoin> queryJoins) { this.queryJoins = queryJoins; } }
public abstract class RestrictedExampleEntityQuery<E> extends ExampleEntityQuery<E> { private static final long serialVersionUID = -5768415674705835414L; @Override protected String buildEjbql() { /** * 由于restrictionæ–¹å¼�里é�¢å�ªèƒ½ä½¿ç”¨å›ºå®šç»“构的ã€�且å�ªæ”¯æŒ�一个å�‚æ•°çš„ã€�且之间是and关系的 QL * å�—æ¤é™�制,暂且将行实例æ�¡ä»¶è¡¨è¾¾å¼�作为主QL的一部分 */ StringBuffer builder = new StringBuffer().append(super.buildEjbql()); if (WHERE_PATTERN.matcher(builder).find()) { builder.append(" and "); } else { builder.append(" where "); } builder.append(getRestrictedQl()); return builder.toString(); } protected String getRestrictedQl() { return EntityQuerySecurityRestriction.getRestrictionQl(ReflectionsUtils .getClassParameterType(getClass(), 0)); } }