HHH-11025 - Document relation traversal api. (cherry picked from commit 6be8232
)
This commit is contained in:
parent
4649f5fa91
commit
129a7085fa
|
@ -626,6 +626,119 @@ Other queries (also accessible from `org.hibernate.envers.CrossTypeRevisionChang
|
||||||
|
|
||||||
Note that methods described above can be legally used only when the default mechanism of tracking changed entity names is enabled (see <<envers-tracking-modified-entities-revchanges>>).
|
Note that methods described above can be legally used only when the default mechanism of tracking changed entity names is enabled (see <<envers-tracking-modified-entities-revchanges>>).
|
||||||
|
|
||||||
|
[[envers-querying-entity-relation-jobs]]
|
||||||
|
=== Querying for entities using entity relation joins
|
||||||
|
|
||||||
|
Audit queries support the ability to apply constraints, projections, and sort operations based on entity relations. In order
|
||||||
|
to traverse entity relations through an audit query, you must use the relation traversal API with a join type.
|
||||||
|
|
||||||
|
[IMPORTANT]
|
||||||
|
====
|
||||||
|
Relation join queries are considered experimental and may change in future releases.
|
||||||
|
====
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
Relation joins can only be applied to `*-to-one` mappings and can only be specified using `JoinType.LEFT` or
|
||||||
|
`JoinType.INNER`.
|
||||||
|
====
|
||||||
|
|
||||||
|
The basis for creating an entity relation join query is as follows:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
// create an inner join query
|
||||||
|
AuditQuery query = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Car.class, 1 )
|
||||||
|
.traverseRelation( "owner", JoinType.INNER );
|
||||||
|
|
||||||
|
// create a left join query
|
||||||
|
AuditQuery query = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Car.class, 1 )
|
||||||
|
.traverseRelation( "owner", JoinType.LEFT );
|
||||||
|
----
|
||||||
|
|
||||||
|
Like any other query, constraints may be added to restrict the results. For example, to find all `Car` entities that
|
||||||
|
have an owner with a name starting with `Joe`, you would use:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
AuditQuery query = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Car.class, 1 )
|
||||||
|
.traverseRelation( "owner", JoinType.INNER )
|
||||||
|
.add( AuditEntity.property( "name" ).like( "Joe%" ) );
|
||||||
|
----
|
||||||
|
|
||||||
|
It is also possible to traverse beyond the first relation in an entity graph. For example, to find all `Car` entities
|
||||||
|
where the owner's address has a street number that equals `1234`:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
AuditQuery query = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Car.class, 1 )
|
||||||
|
.traverseRelation( "owner", JoinType.INNER )
|
||||||
|
.traverseRelation( "address", JoinType.INNER )
|
||||||
|
.add( AuditEntity.property( "streetNumber" ).eq( 1234 ) );
|
||||||
|
----
|
||||||
|
|
||||||
|
Complex constraints may also be added that are applicable to properties of nested relations or the base query entity or
|
||||||
|
relation state, such as testing for `null`. For example, the following query illustrates how to find all `Car` entities where
|
||||||
|
the owner's age is `20` or that the car has _no_ owner:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
AuditQuery query = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Car.class, 1 )
|
||||||
|
.traverseRelation( "owner", JoinType.LEFT, "p" )
|
||||||
|
.up()
|
||||||
|
.add(
|
||||||
|
AuditEntity.or(
|
||||||
|
AuditEntity.property( "p", "age" ).eq( 20 ),
|
||||||
|
AuditEntity.relatedId( "owner" ).eq( null )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.addOrder( AuditEntity.property( "make" ).asc() );
|
||||||
|
----
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
Queries can use the `up` method to navigate back up the entity graph.
|
||||||
|
====
|
||||||
|
|
||||||
|
Disjunction criterion may also be applied to relation join queries. For example, the following query will find all
|
||||||
|
`Car` entities where the owner's age is `20` or that the owner lives at an address where the street number equals `1234`:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
AuditQuery query = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Car.class, 1 )
|
||||||
|
.traverseRelation( "owner", JoinType.INNER, "p" )
|
||||||
|
.traverseRelation( "address", JoinType.INNER, "a" )
|
||||||
|
.up()
|
||||||
|
.up()
|
||||||
|
.add(
|
||||||
|
AuditEntity.disjunction()
|
||||||
|
.add( AuditEntity.property( "p", "age" ).eq( 20 ) )
|
||||||
|
.add( AuditEntity.property( "a", "streetNumber" ).eq( 1234 )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.addOrder( AuditEntity.property( "make" ).asc() );
|
||||||
|
----
|
||||||
|
|
||||||
|
Lastly, this example illustrates how related entity properties can be compared as a constraint. This query shows how to
|
||||||
|
find the `Car` entities where the owner's `age` equals the `streetNumber` of where the owner lives:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
AuditQuery query = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Car.class, 1 )
|
||||||
|
.traverseRelation( "owner", JoinType.INNER, "p" )
|
||||||
|
.traverseRelation( "address", JoinType.INNER, "a" )
|
||||||
|
.up()
|
||||||
|
.up()
|
||||||
|
.add( AuditEntity.property( "p", "age" ).eqProperty( "a", "streetNumber" ) );
|
||||||
|
----
|
||||||
|
|
||||||
=== Conditional auditing
|
=== Conditional auditing
|
||||||
|
|
||||||
Envers persists audit data in reaction to various Hibernate events (e.g. `post update`, `post insert`, and so on), using a series of event listeners from the `org.hibernate.envers.event.spi` package.
|
Envers persists audit data in reaction to various Hibernate events (e.g. `post update`, `post insert`, and so on), using a series of event listeners from the `org.hibernate.envers.event.spi` package.
|
||||||
|
@ -776,7 +889,7 @@ alter table Person
|
||||||
[[envers-mappingexceptions]]
|
[[envers-mappingexceptions]]
|
||||||
=== Mapping exceptions
|
=== Mapping exceptions
|
||||||
|
|
||||||
=== What isn't and will not be supported
|
==== What isn't and will not be supported
|
||||||
|
|
||||||
Bags are not supported because they can contain non-unique elements.
|
Bags are not supported because they can contain non-unique elements.
|
||||||
Persisting, a bag of `String`s violates the relational database principle that each table is a set of tuples.
|
Persisting, a bag of `String`s violates the relational database principle that each table is a set of tuples.
|
||||||
|
@ -789,7 +902,7 @@ There are at least two ways out if you need bag semantics:
|
||||||
. use an indexed collection, with the `@javax.persistence.OrderColumn` annotation
|
. use an indexed collection, with the `@javax.persistence.OrderColumn` annotation
|
||||||
. provide a unique id for your elements with the `@CollectionId` annotation.
|
. provide a unique id for your elements with the `@CollectionId` annotation.
|
||||||
|
|
||||||
=== What isn't and _will_ be supported
|
==== What isn't and _will_ be supported
|
||||||
|
|
||||||
. Bag style collections with a `@CollectionId` identifier column (see https://hibernate.atlassian.net/browse/HHH-3950[HHH-3950]).
|
. Bag style collections with a `@CollectionId` identifier column (see https://hibernate.atlassian.net/browse/HHH-3950[HHH-3950]).
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue