HHH-10762 - Document relation traversal api.
This commit is contained in:
parent
a59ebb7e53
commit
6be82328b5
|
@ -628,6 +628,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>>).
|
||||
|
||||
[[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
|
||||
|
||||
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.
|
||||
|
@ -784,7 +897,7 @@ alter table Person
|
|||
[[envers-mappingexceptions]]
|
||||
=== 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.
|
||||
Persisting, a bag of `String`s violates the relational database principle that each table is a set of tuples.
|
||||
|
@ -797,7 +910,7 @@ There are at least two ways out if you need bag semantics:
|
|||
. use an indexed collection, with the `@javax.persistence.OrderColumn` 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]).
|
||||
|
||||
|
|
Loading…
Reference in New Issue