HHH-11886 - Elaborate Envers documentation and switch to actual source code examples
Provide two examples for the entity type change revision tracking
This commit is contained in:
parent
fa81aafb28
commit
e56ecc24ff
|
@ -505,7 +505,7 @@ The method accepts a `persist` parameter indicating whether the revision entity
|
|||
[[envers-tracking-modified-entities-revchanges]]
|
||||
=== Tracking entity names modified during revisions
|
||||
|
||||
By default entity types that have been changed in each revision are not being tracked.
|
||||
By default, entity types that have been changed in each revision are not being tracked.
|
||||
This implies the necessity to query all tables storing audited data in order to retrieve changes made during specified revision.
|
||||
Envers provides a simple mechanism that creates `REVCHANGES` table which stores entity names of modified persistent objects.
|
||||
Single record encapsulates the revision identifier (foreign key to `REVINFO` table) and a string value.
|
||||
|
@ -516,33 +516,18 @@ Tracking of modified entity names can be enabled in three different ways:
|
|||
In this case `org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity` will be implicitly used as the revision log entity.
|
||||
. Create a custom revision entity that extends `org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity` class.
|
||||
+
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@RevisionEntity
|
||||
public class ExtendedRevisionEntity extends DefaultTrackingModifiedEntitiesRevisionEntity {
|
||||
...
|
||||
}
|
||||
include::{sourcedir}/EntityTypeChangeAuditDefaultTrackingTest.java[tags=envers-tracking-modified-entities-revchanges-example]
|
||||
----
|
||||
+
|
||||
. Mark an appropriate field of a custom revision entity with `@org.hibernate.envers.ModifiedEntityNames` annotation.
|
||||
The property is required to be of `Set<String>` type.
|
||||
+
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@RevisionEntity
|
||||
public class AnnotatedTrackingRevisionEntity {
|
||||
...
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable( name = "REVCHANGES", joinColumns = @JoinColumn( name = "REV" ) )
|
||||
@Column( name = "ENTITYNAME" )
|
||||
@ModifiedEntityNames
|
||||
private Set<String> modifiedEntityNames;
|
||||
|
||||
...
|
||||
}
|
||||
include::{sourcedir}/EntityTypeChangeAuditTest.java[tags=envers-tracking-modified-entities-revchanges-example]
|
||||
----
|
||||
+
|
||||
|
||||
Users, that have chosen one of the approaches listed above,
|
||||
can retrieve all entities modified in a specified revision by utilizing API described in <<envers-tracking-modified-entities-queries>>.
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.userguide.envers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
|
||||
import org.hibernate.envers.RevisionEntity;
|
||||
import org.hibernate.jpa.boot.spi.Bootstrap;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class EntityTypeChangeAuditDefaultTrackingTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Customer.class,
|
||||
AnnotatedTrackingRevisionEntity.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycle() {
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Customer customer = new Customer();
|
||||
customer.setId( 1L );
|
||||
customer.setFirstName( "John" );
|
||||
customer.setLastName( "Doe" );
|
||||
|
||||
entityManager.persist( customer );
|
||||
} );
|
||||
|
||||
EntityManagerFactory entityManagerFactory = null;
|
||||
try {
|
||||
Map settings = buildSettings();
|
||||
settings.put(
|
||||
org.hibernate.jpa.AvailableSettings.LOADED_CLASSES,
|
||||
Arrays.asList(
|
||||
ApplicationCustomer.class,
|
||||
AnnotatedTrackingRevisionEntity.class
|
||||
)
|
||||
);
|
||||
settings.put(
|
||||
AvailableSettings.HBM2DDL_AUTO,
|
||||
"update"
|
||||
);
|
||||
entityManagerFactory = Bootstrap.getEntityManagerFactoryBuilder(
|
||||
new TestingPersistenceUnitDescriptorImpl( getClass().getSimpleName() ),
|
||||
settings
|
||||
).build().unwrap( SessionFactoryImplementor.class );
|
||||
|
||||
final EntityManagerFactory emf = entityManagerFactory;
|
||||
|
||||
doInJPA( () -> emf, entityManager -> {
|
||||
ApplicationCustomer customer = new ApplicationCustomer();
|
||||
customer.setId( 2L );
|
||||
customer.setFirstName( "John" );
|
||||
customer.setLastName( "Doe Jr." );
|
||||
|
||||
entityManager.persist( customer );
|
||||
} );
|
||||
}
|
||||
finally {
|
||||
if ( entityManagerFactory != null ) {
|
||||
entityManagerFactory.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Audited
|
||||
@Entity(name = "Customer")
|
||||
public static class Customer {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
@Temporal( TemporalType.TIMESTAMP )
|
||||
@Column(name = "created_on")
|
||||
@CreationTimestamp
|
||||
private Date createdOn;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Date getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
public void setCreatedOn(Date createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
}
|
||||
}
|
||||
|
||||
@Audited
|
||||
@Entity(name = "Customer")
|
||||
public static class ApplicationCustomer {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
@Temporal( TemporalType.TIMESTAMP )
|
||||
@Column(name = "created_on")
|
||||
@CreationTimestamp
|
||||
private Date createdOn;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Date getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
public void setCreatedOn(Date createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
}
|
||||
}
|
||||
|
||||
//tag::envers-tracking-modified-entities-revchanges-example[]
|
||||
@Entity(name = "AnnotatedTrackingRevisionEntityListener")
|
||||
@Table(name = "TRACKING_REV_INFO")
|
||||
@RevisionEntity
|
||||
public static class AnnotatedTrackingRevisionEntity
|
||||
extends DefaultTrackingModifiedEntitiesRevisionEntity {
|
||||
|
||||
}
|
||||
//end::envers-tracking-modified-entities-revchanges-example[]
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.userguide.envers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.hibernate.envers.DefaultRevisionEntity;
|
||||
import org.hibernate.envers.ModifiedEntityNames;
|
||||
import org.hibernate.envers.RevisionEntity;
|
||||
import org.hibernate.jpa.boot.spi.Bootstrap;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class EntityTypeChangeAuditTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Customer.class,
|
||||
AnnotatedTrackingRevisionEntity.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycle() {
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Customer customer = new Customer();
|
||||
customer.setId( 1L );
|
||||
customer.setFirstName( "John" );
|
||||
customer.setLastName( "Doe" );
|
||||
|
||||
entityManager.persist( customer );
|
||||
} );
|
||||
|
||||
EntityManagerFactory entityManagerFactory = null;
|
||||
try {
|
||||
Map settings = buildSettings();
|
||||
settings.put(
|
||||
org.hibernate.jpa.AvailableSettings.LOADED_CLASSES,
|
||||
Arrays.asList(
|
||||
ApplicationCustomer.class,
|
||||
AnnotatedTrackingRevisionEntity.class
|
||||
)
|
||||
);
|
||||
settings.put(
|
||||
AvailableSettings.HBM2DDL_AUTO,
|
||||
"update"
|
||||
);
|
||||
entityManagerFactory = Bootstrap.getEntityManagerFactoryBuilder(
|
||||
new TestingPersistenceUnitDescriptorImpl( getClass().getSimpleName() ),
|
||||
settings
|
||||
).build().unwrap( SessionFactoryImplementor.class );
|
||||
|
||||
final EntityManagerFactory emf = entityManagerFactory;
|
||||
|
||||
doInJPA( () -> emf, entityManager -> {
|
||||
ApplicationCustomer customer = new ApplicationCustomer();
|
||||
customer.setId( 2L );
|
||||
customer.setFirstName( "John" );
|
||||
customer.setLastName( "Doe Jr." );
|
||||
|
||||
entityManager.persist( customer );
|
||||
} );
|
||||
}
|
||||
finally {
|
||||
if ( entityManagerFactory != null ) {
|
||||
entityManagerFactory.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Audited
|
||||
@Entity(name = "Customer")
|
||||
public static class Customer {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
@Temporal( TemporalType.TIMESTAMP )
|
||||
@Column(name = "created_on")
|
||||
@CreationTimestamp
|
||||
private Date createdOn;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Date getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
public void setCreatedOn(Date createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
}
|
||||
}
|
||||
|
||||
@Audited
|
||||
@Entity(name = "Customer")
|
||||
public static class ApplicationCustomer {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
@Temporal( TemporalType.TIMESTAMP )
|
||||
@Column(name = "created_on")
|
||||
@CreationTimestamp
|
||||
private Date createdOn;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Date getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
public void setCreatedOn(Date createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
}
|
||||
}
|
||||
|
||||
//tag::envers-tracking-modified-entities-revchanges-example[]
|
||||
@Entity(name = "AnnotatedTrackingRevisionEntityListener")
|
||||
@Table(name = "TRACKING_REV_INFO")
|
||||
@RevisionEntity
|
||||
public static class AnnotatedTrackingRevisionEntity extends DefaultRevisionEntity {
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(
|
||||
name = "REVCHANGES",
|
||||
joinColumns = @JoinColumn( name = "REV" )
|
||||
)
|
||||
@Column( name = "ENTITYNAME" )
|
||||
@ModifiedEntityNames
|
||||
private Set<String> modifiedEntityNames = new HashSet<>();
|
||||
|
||||
public Set<String> getModifiedEntityNames() {
|
||||
return modifiedEntityNames;
|
||||
}
|
||||
}
|
||||
//end::envers-tracking-modified-entities-revchanges-example[]
|
||||
}
|
Loading…
Reference in New Issue