Any object that implements org.objectstyle.cayenne.query.Query interface can be executed with a DataContext.
The interface defines the following methods (ommitting irrelevant deprecated ones):
- getName returns a symbolic name of the query. The name may be used as a key to find queries stored in the DataMap. Some query implementors reuse the name as a QueryMetadata cache key. Generally the name can be null.
- getMetaData is called at various stages of the execution by Cayenne access stack to retrieve query parameters. EntityResolver instance is passed to this method, meaning that the query doesn't need to store direct references to Cayenne mapping objects and can resolve them at runtime.
- route is invoked when Cayenne decides which DataNode (database) to use when running a query. Routing decision is made by the Query istelf by calling QueryRouter.route(..). This is an important extension point. For instance all Cayenne "indirect" queries implement this method to create (or somehow resolve) one or more substitute queries and route them instead of self.
- createSQLAction allows to fully customize Query execution at the JDBC level. In the simplest case an implementor calls one of the methods on SQLActionVisitor to return a standard action for a specific type of query. However it can provide its own SQLAction that accesses the database in some special way.
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.objectstyle.cayenne.query.IndirectQuery. As an example lets implement a "CountQuery" query that returns a number of rows in a given table:
Now you can run the query like that:
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.