Form Query

A query form is an EntityBackingBean in query view where users can specify query criteria using editable properties of the EntityBackingBean. Query crieteria can be built from query properties, and query results will be shown as 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.

Property Types

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 alway 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;
	}
	
}

Query View

Create an EntityBackingBean in query view. For example, create and show an ExpenseClaim query form 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 must be annotated with the views that contain ViewType.QUERY in order for them to be shown in query form. 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 not default), whether a property can be group-by property, order-by property 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)))

Group By

For a group-by query, the query results are aggregate values of numeric properites. For example, in ExampleHR 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.

public class ExpenseClaimBean extends EntityBackingBean<ExpenseClaim> {
     
	@Override
	public StatisticsProperty[] getStatisticsProperties() {
		return new StatisticsProperty[]{
			new StatisticsProperty(ExpenseClaim.PROPERTY_TOTAL_EXPENSE, Aggregate.SUM)}; 
	}
}

Order By

If order-by is not specified in the search options of a form query, default orders will be used. The default order is ordering results by nid/hierarchyId/id descending, createdDate descending if the entity type implements CreatedDateAware. For a group-by query, the order-by property can be the 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 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,

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. If a joinType is not specified for a property path, it defaults to inner join.

Property Query Criterion

The query criteria built for a query form 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)))

Open Query Form

When a menu node is created by a MenuNodeFactory from a TypeDescriptor of an entity type, whether query is enabled can be specified. For example,

public class HrMenuNodeFactory extends ModuleMenuNodeFactory {
	@Override
	protected void createSubMenu() throws SystemException {
		TypeDescriptorp[] types = new TypeDescriptor[] {
			new TypeDescriptor<Employee>(Employee.class, 
				null, viewConfig, null, true, null, null)};
		addTypedMenuNodes(this, rootMenuNode, types);
	}
}
If query is enabled, query form can be opened from the submenu of the menu node.

The render regions of a query form can be specified by the queryRenderRegions of a TypeDescriptor. ContainerBean.getDefaultQueryRenderRegions() provides the default render regions to show the query form in the containerBean.

Query form can also be opened from query results to refine search if the query form bean can be obtained from its EntityDataSource by EntityDataSource.getQueryFormBean().

Search Command Ajax Behavior

By default, the Search command is ajax 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 ajax 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 Tabs

A query form has 3 tabs: Quick, Advanced and Search options. The default quick query properties are the query properties shown in dialog and keyword query property.

To change the default, override the getQuickQueryProperties() method of EntityBackingBean. Those properties not in the Quick tab will be grouped under the Advanced tab.


	@Override
	protected List<String> getQuickQueryProperties() {
		return CollectionUtil.convertToList("name", "type", KeywordEntityProperty.NAME);
	}