HHH-11886 - Elaborate Envers documentation and switch to actual source code examples

Add examples about reading revisions and reconstructing entity state
This commit is contained in:
Vlad Mihalcea 2017-07-25 14:28:14 +03:00
parent d671fe1391
commit 7c5213171b
4 changed files with 185 additions and 1 deletions

View File

@ -106,7 +106,81 @@ The `REVTYPE` column value is taken from the https://docs.jboss.org/hibernate/or
|=================================
The audit (history) of an entity can be accessed using the `AuditReader` interface, which can be obtained having an open `EntityManager` or `Session` via the `AuditReaderFactory`.
See the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/envers/AuditReaderFactory.html[Javadocs] for these classes for details on the functionality offered.
[[envers-audited-revisions-example]]
.Getting a list of revisions for the `Customer` entity
====
[source, JAVA, indent=0]
----
include::{sourcedir}/AuditTest.java[tags=envers-audited-revisions-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/envers-audited-revisions-example.sql[]
----
====
Using the previously fetched revisions, we can now inspect the state of the `Customer` entity at that particular revision:
[[envers-audited-rev1-example]]
.Getting the first revision for the `Customer` entity
====
[source, JAVA, indent=0]
----
include::{sourcedir}/AuditTest.java[tags=envers-audited-rev1-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/envers-audited-rev1-example.sql[]
----
====
When executing the aforementioned SQL query, there are two parameters:
revision_number::
The first parameter marks the revision number we are interested in or the latest one that exist up to this particular revision.
revision_type::
The second parameter specifies that we are not interested in `DEL` `RevisionType` so that deleted entries are filtered out.
The same goes for the second revision associated to the `UPDATE` statement.
[[envers-audited-rev2-example]]
.Getting the second revision for the `Customer` entity
====
[source, JAVA, indent=0]
----
include::{sourcedir}/AuditTest.java[tags=envers-audited-rev2-example]
----
====
For the deleted entity revision, Envers throws a `NoResultException` since the entity was no longer valid at that revision.
[[envers-audited-rev3-example]]
.Getting the third revision for the `Customer` entity
====
[source, JAVA, indent=0]
----
include::{sourcedir}/AuditTest.java[tags=envers-audited-rev3-example]
----
====
You can use the
https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/envers/AuditReader.html#find-java.lang.Class-java.lang.String-java.lang.Object-java.lang.Number-boolean-[`find(Class<T> cls, String entityName, Object primaryKey, Number revision, boolean includeDeletions)`]
method to get the deleted entity revision so that, instead of a `NoResultException`,
all attributes, except for the entity identifier, are going to be `null`.
[[envers-audited-rev4-example]]
.Getting the third revision for the `Customer` entity without getting a `NoResultException`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/AuditTest.java[tags=envers-audited-rev4-example]
----
====
See the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/envers/AuditReader.html[Javadocs] for details on other functionality offered.
[[envers-configuration]]
=== Configuration

View File

@ -0,0 +1,23 @@
select
c.id as id1_1_,
c.REV as REV2_1_,
c.REVTYPE as REVTYPE3_1_,
c.created_on as created_4_1_,
c.firstName as firstNam5_1_,
c.lastName as lastName6_1_
from
Customer_AUD c
where
c.REV = (
select
max( c_max.REV )
from
Customer_AUD c_max
where
c_max.REV <= ?
and c.id = c_max.id
)
and c.REVTYPE <> ?
-- binding parameter [1] as [INTEGER] - [1]
-- binding parameter [2] as [INTEGER] - [2]

View File

@ -0,0 +1,13 @@
select
c.REV as col_0_0_
from
Customer_AUD c
cross join
REVINFO r
where
c.id = ?
and c.REV = r.REV
order by
c.REV asc
-- binding parameter [1] as [BIGINT] - [1]

View File

@ -7,19 +7,29 @@
package org.hibernate.userguide.envers;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.hibernate.envers.Audited;
import org.hibernate.envers.exception.AuditException;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.test.legacy.Custom;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
/**
* @author Vlad Mihalcea
@ -59,6 +69,70 @@ public class AuditTest extends BaseEntityManagerFunctionalTestCase {
entityManager.remove( customer );
//end::envers-audited-delete-example[]
} );
//tag::envers-audited-revisions-example[]
List<Number> revisions = doInJPA( this::entityManagerFactory, entityManager -> {
return AuditReaderFactory.get( entityManager ).getRevisions(
Customer.class,
1L
);
} );
//end::envers-audited-revisions-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::envers-audited-rev1-example[]
Customer customer = (Customer) AuditReaderFactory.get( entityManager )
.createQuery()
.forEntitiesAtRevision( Customer.class, revisions.get( 0 ) )
.getSingleResult();
assertEquals("Doe", customer.getLastName());
//end::envers-audited-rev1-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::envers-audited-rev2-example[]
Customer customer = (Customer) AuditReaderFactory.get( entityManager )
.createQuery()
.forEntitiesAtRevision( Customer.class, revisions.get( 1 ) )
.getSingleResult();
assertEquals("Doe Jr.", customer.getLastName());
//end::envers-audited-rev2-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::envers-audited-rev3-example[]
try {
Customer customer = (Customer) AuditReaderFactory.get( entityManager )
.createQuery()
.forEntitiesAtRevision( Customer.class, revisions.get( 2 ) )
.getSingleResult();
fail("The Customer was deleted at this revision: " + revisions.get( 2 ));
}
catch (NoResultException expected) {
}
//end::envers-audited-rev3-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::envers-audited-rev4-example[]
Customer customer = (Customer) AuditReaderFactory.get( entityManager )
.createQuery()
.forEntitiesAtRevision(
Customer.class,
Customer.class.getName(),
revisions.get( 2 ),
true )
.getSingleResult();
assertEquals( Long.valueOf( 1L ), customer.getId() );
assertNull( customer.getFirstName() );
assertNull( customer.getLastName() );
assertNull( customer.getCreatedOn() );
//end::envers-audited-rev4-example[]
} );
}
//tag::envers-audited-mapping-example[]