Cmobilecom AF 5.19 Developer Guide

7.10 Query Bean

A query bean is an EntityBackingBean in query view where users can specify query criteria using editable properties of the EntityBackingBean. Query criteria will be built from query properties, and query results will be shown as an EntityListBackingBean with a pageable entity list. Search options allow users to specify group-by, order-by and page size options. In case of group-by query, the query results are aggregate values of numeric properties.

Query Property Types

Property types can be any type supported by JPA, including basic and entity types. Query bean supports formBeanProperties (nested beans), and query property path can be multiple levels. For example, user can select employee.address.state from ExpenseClaim query bean.
	ExpenseClaim -> Employee -> Address (street, city, state, zipCode, country)
If a property value is not null, it will be added in query criteria. So entity property type must not be a primitive type since it will always have a default value (e.g. false for boolean, 0 for integer). So use its wrapper type instead. For example,

public class Employee {

	private Boolean partTime;
	
	@Column(nullable=false)
	public Boolean getPartTime() {
		return this.partTime;
	}
	
	public void setPartTime(Boolean partTime) {
		this.partTime = partTime;
	}
	
}

Create Query Bean

Create a query EntityBackingBean in the same way as creating one for persisting a new entity or showing an existing entity except different ViewType(QUERY). For example, create and show an ExpenseClaim query bean in the specified render regions of a ContainerBean (ContainerRenderRegions):

	public PageNavigation showExpenseClaimQuery(ContainerRenderRegions containerRenderRegions) {
		EntityViewConfig viewConfig = new EntityViewConfig(ViewType.QUERY);
		ExpenseClaim expenseClaim = new ExpenseClaim();
		EntityDataSource entityDataSource = new EntityDataSource(expenseClaim);
		entityDataSource.setRenderRegions(containerRenderRegions);
		ContainerBean containerBean = containerRenderRegions.getTargetContainerBean();
		return containerBean.showEntity(ExpenseClaim.class, entityDataSource, viewConfig, false);
	}

Query Property Annotations

Query properties are those EntityProperty annotations that contain ViewType.QUERY. ViewType.ALL contains all view types including ViewType.QUERY. For example,

	view={ViewType.ALL}
	view={ViewType.QUERY}
	view={ViewType.ENTITY, ViewType.QUERY}
@Query annotation specifies EntityProperty type (if different from ViewType.ENTITY), render style(if different from ViewType.ENTITY), whether a property can be group-by, order-by and/or keyword matching property, match type, etc. For example,

	@Property(name="summary", view={ViewType.ALL},
		renderStyle=@RenderStyleDef(size=30),
		query=@Query(keyword=true)),
		
	@Property(name="description", view={ViewType.ENTITY, ViewType.QUERY},
		renderStyle=@RenderStyleDef(style=RenderStyle.INPUT_HTML),
		query=@Query(keyword=true)),		
		
	@Property(name="employee", view={ViewType.ALL},
		query=@Query(groupByProperty=true, orderByProperty=true)),
		
	@Property(name="createdDate", view={ViewType.ALL},
		mode={ModeType.VIEW, ModeType.EDIT, ModeType.QUERY}, editable=EditControl.QUERY_ONLY,
		query=@Query(entityPropertyType=RangeEntityProperty.class, orderByProperty=true,
			renderStyle=@RenderStyleDef(size=8)))
Query properties can be controlled by query ViewConfig. For example,

	EntityViewConfig queryViewConfig = new EntityViewConfig(ViewType.QUERY);
	queryViewConfig.setPropertiesToShow("name", "type");
	//queryViewConfig.setPropertiesToHide("name", "type");

Group By

For a group-by query, the query results are aggregate values of numeric properties. For example, in the example HR module, list total expenses group by employee, order by employee total expense descending. The numeric aggregate properties for group-by are specified as StatisticsProperty(s) that are also used to calculate statistics row in a pageable entity list bean.

public class ExpenseClaimBean extends EntityBackingBean<ExpenseClaim> {
     
	@Override
	public StatisticsProperty[] getStatisticsProperties() {
		return new StatisticsProperty[]{
			new StatisticsProperty(ExpenseClaim.PROPERTY_TOTAL_EXPENSE, Aggregate.SUM)}; 
	}
}
Multiple group-by properties can be selected by user from search options.

Order By

Multiple order-by properties can be selected by user from search options of a query bean. If none of order-by properties are selected, default orders will be used, which are ordering results by nid/hierarchyId/id descending, createdDate descending if the entity type implements CreatedDateAware. For a group-by query, an order-by property can be a group-by property or an aggregate property.

To override default orders, for example, order by employee type ascending and hiredDate descending:


public class EmployeeBean extends EntityBackingBean<Employee> {
	@Override
	public List<CriteriaOrder> getDefaultQueryOrders() {
		List<CriteriaOrder> orders = new ArrayList<CriteriaOrder>(2);
		
		orders.add(DetachedCriteria.asc("type"));
		orders.add(DetachedCriteria.desc("hiredDate"));
		return orders;
	}
}
To add entity default query orders to a QueryCriteria for building a CriteriaQuery,

	CriteriaQueryBuilder builder = ;
	// add default orders
	EntityDefaultOrdersBuilder<Employee, Employee> defaultOrdersBuilder = 
		new EntityDefaultOrdersBuilder<Employee, Employee>(Employee, null, containerBean);		
	QueryCriteria<Employee, Employee> queryCriteria = new QueryCriteria<Employee, Employee>(
		Employee.class, Employee.class, builder, defaultOrdersBuilder);

Query Join Graph

The default join types in building a CriteriaQuery are inner joins. To use outer joins for certain property paths, override getQueryJoinTypes() method of EntityBackingBean. For example, search from ExpenseClaimItem query bean, ExpenseClaimItem inner join ExpenseClaim inner join Employee left join Address.

public class ExpenseClaimItemBean extends EntityBackingBean<ExpenseClaimItem> {
	@Override
	public EntityJoinGraph<ExpenseClaimItem> getQueryJoinGraph() {
		return new EntityJoinGraph<ExpenseClaimItem>(ExpenseClaimItem.class,
			new Object[]{"expenseClaim.employee.address", JoinType.LEFT}
			);
	}
}
All entity joins are inner joins except that expenseClaim.employee left outer joins address.

Property Query Criterion

The query criteria built for a query bean is the conjunction of property query restrictions. The default restriction for a query property depends on its property type: The matchType of @Query annotation can change the default match, such as CriteriaFunction.Function.START_WITH, CriteriaFunction.Function.LESS_THAN, etc.

To change the default query criterion for a property, for example, a custom property, override the getQueryCriterion(...) method of EntityBackingBean.


	@Override
	public <Q> PropertyQueryCriterion getQueryCriterion(CriteriaBuilder criteriaBuilder, 
  			CriteriaQuery<Q> criteriaQuery,
  			EntityProperty<T> queryProperty) throws SystemException {
		if (queryProperty.getName().equals("customProperty")) {		
			Predicate criterion = ;
			return new PropertyQueryCriterion(criterion, false);
		}
  	
		return super.getQueryCriterion(criteriaBuilder, criteriaQuery, queryProperty);
	}

Null or notNull Restrictions

To add null or notNull restriction of a property, the EntityProperty subclass CheckNotNullProperty can be used. For example, list the employees whose home addresses are null or not null.

	@Property(name="homeAddress", view={ViewType.ENTITY, ViewType.QUERY},
		query=@Query(entityPropertyType=CheckNotNullProperty.class,
			renderStyle=@RenderStyleDef(style=RenderStyle.SELECT_ONE_MENU)))

Enable Entity Query From Menu Node

When a menu node is created by a TypedMenuNodeFactory from a TypeDescriptor of an entity type, whether query is enabled can be specified. For example, to enable query for Employee entities,

public class HrMenuNodeFactory extends ModuleMenuNodeFactory {
	@Override
	protected void createSubMenu() throws SystemException {
		TypeDescriptor[] types = new TypeDescriptor[] {
			new TypeDescriptor<Employee>(Employee.class, 
				null, viewConfig, null, true, null, null)};
		addTypedMenuNodes(this, rootMenuNode, types);
	}
}

If query is enabled, a query bean can be opened from the submenu of the menu node. The render regions of a query bean can be specified by the queryRenderRegions of a TypeDescriptor. ContainerBean.getDefaultQueryRenderRegions() provides the default render regions to show the query bean in the containerBean. Query bean can also be opened from query results bean to refine search results if the query bean can be obtained from its EntityDataSource by EntityDataSource.getQueryFormBean().

Search Command Partial Behavior

By default, the Search command is partial behavior enabled and show the query results in the default query results regions:

	ContainerBean.getDefaultQueryResultRenderRegions()
To show query results in different regions or containerBean, change the render regions of the Search command partial behavior. For example,

public class MyBackingBean extends EntityBackingBean<MyType> {
	@Override
	public void refreshMenuBeans() throws BackingBeanException, SystemException {
		super.refreshMenuBeans();

		if (!viewConfig.isQueryView())
			return;
			
		String queryCommand = getQueryCommand();	
  		MenuNode searchMenuNode = getMenuNode(queryCommand, false, true);
   		PartialBehaviorSupport partialBehaviorSupport = searchMenuNode.getPartialBehaviorSupport();
  		PartialBehavior partialBehavior = partialBehaviorSupport.getPartialBehavior(PartialBehavior.EVENT_ACTION, false);
  		ContainerRenderRegions queryResultsRenderRegions = ;
  		partialBehavior.setContainerRenderRegions(queryResultsRenderRegions);
  	}
}

Quick, Advanced and Search Options

A query bean has three tabs: Quick, Advanced and Search options. The default quick query properties are entity primary properties and keyword query property. To change the default, set quickQueryProperties in query ViewConfig.
	EntityViewConfig queryViewConfig = new EntityViewConfig(ViewType.QUERY);
	queryViewConfig.setQuickQueryProperties("id", "name", "type");
Those properties not in the Quick tab will be grouped under the Advanced tab.

Alternatively, override the getDefaultPrimaryProperties() method of EntityBackingBean.


	@Override
	protected List<String> getDefaultPrimaryProperties(ViewType viewType) {
		return Arrays.asList("id", "name", "type");
	}
Entity primary properties are also used in entity selections dialog for an EntityProperty.
Auto CompletePartial BehaviorFrames / No Frames