Using server queries internally
Overview
This page is aimed at internal server developers and does not contain information for how to perform API queries. If that is the kind of information you are looking for, you may find OMERO Application Programming Interface more useful as a starting point. OME’s Hibernate 3.5 Training additionally provides information on both API queries and server internals.
Introduction
The ome.services.queries package is intended to allow for the easy definition of queries by both developers and clients. Due to the fragility of HQL defined queries, a framework allowing for easy definition, multiple formats (Velocity templates, Database values, class files), and transparent lookup is critical.
Lookup happens among all QuerySources
that are registered with the
QueryFactory
instance present in OMERO services. The first non-null
Query instance returned by a QuerySource
for a given String id is
used.
Queries implement the HibernateCallback
interface and are passed
directly into an HibernateTemplate
instance. Therefore, care should
be taken as to which QuerySources
are registered with the
QueryFactory
.
Parameters
Critical for using queries is the specification of named parameters, number of results to return, offset of the first result to return etc. These features are offered by the ome.parameters package. The ome.parameters.Parameters class is the starting point for building new parameters (although the ome.parameters.Filter object is used by some methods).
To specify parameters, instantiate a Parameters object either with or without a Filter object argument. The version with Filter object is useful for specifying the number of results to be returned and whether or not a java.util.Collection or a ome.model.IObject instance will be returned. For example,
Parameters p = new Parameters( new Filter().unique() );
will specify that the given query should return a single instance. An exception will be thrown if more than one result is found.
Parameters p = new Parameters( new Filter().unique().page(0,1) );
However, this will guarantee that only one result will be returned, since more than 1 result (“maxResults”) will be ignored. Here, an ordering of the results might make sense.
Once a Parameters instance is available, named parameters can be added
using any of the add…()
methods. These parameters will be
dynamically bound during query preparation. For example, a query of the
form:
select e from Experimenter e where omeName = :name
has one named parameter “name”, which can be specified by the call:
parameters.addString("name","<myNameHere>");
Positional parameters of the form
select e from Experimenter where omeName = ?
are not supported.
Adding queries
Subclassing query
Other than by defining String queries via new QueryDef()
TBD, the
easiest way to create queries is to subclass ome.services.query.Query.
The only non-optional requirements on the Query implementor are then to
define the (possibly optional) named parameters to the Query, and to
override the “buildQuery” (which must call one and only one of
“setQuery()” or “setCriteria()”)
Other than that, the Query implementor can enable filters on the Hibernate session (an attempt is made to clean up after the Query runs), and in general use any of the Hibernate session methods.
Defining a QuerySource
A more involved but perhaps more rewarding method would be to implement
QuerySource
and configure QueryFactory
to lookup query ids also
in your QuerySource
. This would allow you to write Velocity (or
Freemarker/Ruby/Python/Groovy…) QuerySources
which use some form
of templating or scripting to generate HQL queries.