Data Provider Module
Package: org.hisp.dhis.service.dataprovider (interface), org.hisp.dhis.service.dataprovider.hibernate (implementation)
Module: dhis-api (interface), dhis-service-dataprovider-hibernate (implementation)
A DataProvider abstracts away how collections of objects are retrieved from an underlying persistence layer. It takes a Specification as an argument, runs a query based on it, and returns an Iterator of the results. The reason for using an Iterator is to allow for conservation of memory by allowing the persistence layer to return one and one object from the result, rather than all at once.
public interface DataProvider
{
Iterator getValueIterator( Specification specification );
}
In DHIS 2 there is one implementation, HibernateDataProvider, which encapsulates a simplified way of getting a collection of objects from Hibernate. Hibernate itself has powerful query facilities, but this interface decouples the use of Hibernate from the rest of the application.
A Specification represents the rules used to retrieve a set of objects from the database. A concrete example is this: Give me all DataValue objects which refer to this OrganisationUnit and this DataElement. The DataProvider will translate such a specification to something the underlying persistence layer can understand. In DHIS 2, the typical case is to construct a Hibernate Query or Criteria object, run it, and return it to the provider.
A Specification object is constructed with one class as it's parameter, meaning which type of object the DataProvider should return:
Specification spec = new Specification ( DataValue.class );
From then on, it's a matter of defining a set of constraints on the selection. No constraints, means all objects of the given class is retrieved. Each constraint relates to one of the fields of the object. It is possible to define three kinds of constraints:
- Equality constraints: The specified field of the object being retrieved must refer to/be equal to the one object given as an argument:
spec.addConstraint( "dataElement", myDataElementObject );
- Collection constraint: The specified field must refer to or be equal to one of the objects in the collection given as an argument.
spec.addConstraint( "dataElement" myDataElementCollection );
- Range constraint: The specified field must be within the given range definitions, for example a start data must be between two given dates.
Notes
- The source field of the DataValue object is automatically aliased to an OrganisationUnit object as this is the common case.
- It is not possible to refer to properties beyond those directly referenced by the object being retrieved. For example, it is not possible to create constraints on the name of an OrganisationUnit object through a Specification based on DataValues. Instead, one could create and run a Specification for OrganisationUnits based on their name, retrieve the results, and add a Collection constraint with the retrieved OrganisationUnit objects on the source field of the DataValue class.