Title: Customizing Queries

Any object that implements org.apache.cayenne.query.Query interface can be executed with a DataContext.

Understanding Query Interface

The interface defines the following methods (ommitting irrelevant deprecated ones):

public interface Query extends Serializable {

    String getName();

    QueryMetadata getMetaData(EntityResolver resolver);

    void route(QueryRouter router, EntityResolver resolver, Query substitutedQuery);

    SQLAction createSQLAction(SQLActionVisitor visitor);
}

Indirect Queries

One customization strategy is an "indirect" query that encapsulates some user-defined operation and in runtime resolves to one or more standard Cayenne queries. Indirect queries can be created from scratch or by extending org.apache.cayenne.query.IndirectQuery. As an example lets implement a "CountQuery" query that returns a number of rows in a given table:

public class CountQuery extends IndirectQuery {
	protected Class objectClass;

	public CountQuery(Class objectClass) {
		this.objectClass = objectClass;
	}

	protected Query createReplacementQuery(EntityResolver resolver) {
		DbEntity entity = resolver.lookupDbEntity(objectClass);

		if (entity == null) {
			throw new CayenneRuntimeException(
					"No entity is mapped for java class: "
							+ objectClass.getName());
		}

		String sql = "SELECT #result('count(*)' 'int' 'C') FROM "
				+ entity.getName();
		SQLTemplate replacement = new SQLTemplate(entity, sql);
		replacement.setFetchingDataRows(true);
		return replacement;
	}
}

Now you can run the query like that:

CountQuery query = new CountQuery(Artist.class);
DataContext context = DataContext.createDataContext();

Map row = (Map) context.performQuery(query).get(0);
System.out.println("Count: " + row.get("C"));

For other real-life examples of indirect queries take a look at the source code of the following Cayenne queries: QueryChain, ObjectIdQuery, RelationshipQuery, NamedQuery.

Subclassing Standard Queries

All standard queries can be subclassed, overriding some of their methods. For instance overriding route and/or createSQLAction would allow to implement custom callbacks at different points of query lifecycle.