Queries

You can think of historic data as having two dimension. The first - horizontal - is the state of the database at a given revision. Thus, you can query for entities as they were at revision N. The second - vertical - are the revisions, at which entities changed. Hence, you can query for revisions, in which a given entity changed.

The queries in Envers are "almost" (as they contain some additional features) a subset of Hibernate Criteria, so if you are common with them, using Envers queries will be much easier.

The main limitation of the current queries implementation is that you cannot traverse relations. You can only specify constraints on the ids of the related entities, and only on the "owning" side of the relation. This however will be changed in future releases.

Please note, that queries on the versioned data will be in many cases much slower than corresponding queries on "live" data, as they involve correlated subselects.

Querying for entities of a class at a given revision

The entry point for this type of queries is:

VersionsQuery query = getVersionsReader().createQuery().forEntitiesAtRevision(
		MyEntity.class, revisionNumber);

You can then specify constraints, which should be met by the entities returned, by adding restrictions, which can be obtained using the VersionsRestrictions factory class. For example, to select only entities, where the "name" property is equal to "John":

query.add(VersionsRestrictions.eq("name", "John"));

And to select only entites that are related to a given entity:

query.add(VersionsRestrictions.eq("address", relatedEntityInstance));
// or
query.add(VersionsRestrictions.relatedIdEq("address", relatedEntityId));

You can limit the number of results, order them, and set aggregations and projections (except grouping) in the usual way. When your query is complete, you can obtain the results by calling the getSingleResult() or getResultList() methods.

A full query, can look for example like this:

List personsAtAddress = getVersionsReader().createQuery()
                .forEntitiesAtRevision(Person.class, 12)
                .addOrder(Order.desc("surname"))
                .add(VersionsRestrictions.relatedIdEq("address", addressId))
                .setFirstResult(4)
                .setMaxResults(2)
                .getResultList();

Querying for revisions, at which entities of a given class changed

The entry point for this type of queries is:

VersionsQuery query = getVersionsReader().createQuery()
                .forRevisionsOfEntity(MyEntity.class, false);

You can add constraints to this query in the same way as to the previous one. There are two additional options. The first one is the RevisionProperty class, which represents the revision number property in a versioned class. Using it, you can order the query results by revision number, set projection or constraint the revision number to be greater or less than a specified value. For example, the following query will select the smallest revision number, at which entity of class MyEntity with id entityId has changed, after revision number 42:

Number revision = (Number) getVersionsReader().createQuery()
                .forRevisionsOfEntity(MyEntity.class, false)
                .setProjection(RevisionProperty.min())
                .add(VersionsRestrictions.idEq(entityId))
                .add(RevisionProperty.ge(42))
                .getSingleResult();

The second additional feature you can use in queries for revisions is the ability to maximalize/minimize a property. For example, if you want to select the revision, at which the value of the actualDate for a given entity was larger then a given value, but as small as possible:

Number revision = (Number) getVersionsReader().createQuery()
                .forRevisionsOfEntity(MyEntity.class, false)
                // We are only interested in the first revision
                .setProjection(RevisionProperty.min()) 
                .add(VersionsRestrictions.minimizeProperty("actualDate")
                    .add(VersionsRestrictions.ge("actualDate", givenDate))
                    .add(VersionsRestrictions.idEq(givenEntityId)))
                .getSingleResult();

The minimizeProperty() and maximizeProperty() methods return a criteria, to which you can add constraints, which must be met by the entities with the maximized/minimized properties.