HHH-7555 - Add ability to query revision entity instances of an entity class without instantiating the entity instances.
(backport from wip/6.0)
This commit is contained in:
parent
4a3f7c19c0
commit
fea7f348ee
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.query;
|
package org.hibernate.envers.query;
|
||||||
|
|
||||||
|
import org.hibernate.Incubating;
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.exception.NotAuditedException;
|
import org.hibernate.envers.exception.NotAuditedException;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
@ -171,7 +172,8 @@ public class AuditQueryCreator {
|
||||||
auditReaderImplementor,
|
auditReaderImplementor,
|
||||||
c,
|
c,
|
||||||
selectEntitiesOnly,
|
selectEntitiesOnly,
|
||||||
selectDeletedEntities
|
selectDeletedEntities,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +213,60 @@ public class AuditQueryCreator {
|
||||||
c,
|
c,
|
||||||
entityName,
|
entityName,
|
||||||
selectEntitiesOnly,
|
selectEntitiesOnly,
|
||||||
selectDeletedEntities
|
selectDeletedEntities,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a query that selects the revision entities associated with the specified entity. You may also
|
||||||
|
* specify whether the revision entities list should include those for deletions of the entity class.
|
||||||
|
*
|
||||||
|
* @param clazz Class of the entities for which to query.
|
||||||
|
* @param selectDeletedEntities If true, the result will include revision entities where deletions occurred.
|
||||||
|
*
|
||||||
|
* @return A query of revision entities based on the specified entity class. The results of the query will
|
||||||
|
* be stored in ascending order by the revision number unless an order is specified.
|
||||||
|
*
|
||||||
|
* @since 5.3
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
public AuditQuery forRevisionsOfEntity(Class<?> clazz, boolean selectDeletedEntities) {
|
||||||
|
clazz = getTargetClassIfProxied( clazz );
|
||||||
|
return new RevisionsOfEntityQuery(
|
||||||
|
enversService,
|
||||||
|
auditReaderImplementor,
|
||||||
|
clazz,
|
||||||
|
false,
|
||||||
|
selectDeletedEntities,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a query that selects the revision entities associated with the specified entity. You may also
|
||||||
|
* specify whether the revision entities list should include those for deletions of the entity class.
|
||||||
|
*
|
||||||
|
* @param clazz Class of the entities for which to query.
|
||||||
|
* @param entityName Name of the entity (for cases where it cannot be guessed based on class clazz).
|
||||||
|
* @param selectDeletedEntities If true, the result will include revision entities where deletions occurred.
|
||||||
|
*
|
||||||
|
* @return A query of revision entities based on the specified entity class. The results of the query will
|
||||||
|
* be stored in ascending order by the revision number unless an order is specified.
|
||||||
|
*
|
||||||
|
* @since 5.3
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
public AuditQuery forRevisionsOfEntity(Class<?> clazz, String entityName, boolean selectDeletedEntities) {
|
||||||
|
clazz = getTargetClassIfProxied( clazz );
|
||||||
|
return new RevisionsOfEntityQuery(
|
||||||
|
enversService,
|
||||||
|
auditReaderImplementor,
|
||||||
|
clazz,
|
||||||
|
entityName,
|
||||||
|
false,
|
||||||
|
selectDeletedEntities,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.exception.AuditException;
|
import org.hibernate.envers.exception.AuditException;
|
||||||
|
import org.hibernate.envers.exception.NotAuditedException;
|
||||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
|
@ -79,6 +80,9 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
||||||
entityClassName = cls.getName();
|
entityClassName = cls.getName();
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
versionsEntityName = enversService.getAuditEntitiesConfiguration().getAuditEntityName( entityName );
|
versionsEntityName = enversService.getAuditEntitiesConfiguration().getAuditEntityName( entityName );
|
||||||
|
if ( !enversService.getEntitiesConfigurations().isVersioned( entityName ) ) {
|
||||||
|
throw new NotAuditedException( entityName, "Entity [" + entityName + "] is not versioned" );
|
||||||
|
}
|
||||||
aliasToEntityNameMap.put( REFERENCED_ENTITY_ALIAS, entityName );
|
aliasToEntityNameMap.put( REFERENCED_ENTITY_ALIAS, entityName );
|
||||||
|
|
||||||
qb = new QueryBuilder( versionsEntityName, REFERENCED_ENTITY_ALIAS );
|
qb = new QueryBuilder( versionsEntityName, REFERENCED_ENTITY_ALIAS );
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.envers.query.internal.impl;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.persistence.criteria.JoinType;
|
import javax.persistence.criteria.JoinType;
|
||||||
|
|
||||||
|
@ -30,17 +31,20 @@ import org.hibernate.proxy.HibernateProxy;
|
||||||
public class RevisionsOfEntityQuery extends AbstractAuditQuery {
|
public class RevisionsOfEntityQuery extends AbstractAuditQuery {
|
||||||
private final boolean selectEntitiesOnly;
|
private final boolean selectEntitiesOnly;
|
||||||
private final boolean selectDeletedEntities;
|
private final boolean selectDeletedEntities;
|
||||||
|
private final boolean selectRevisionInfoOnly;
|
||||||
|
|
||||||
public RevisionsOfEntityQuery(
|
public RevisionsOfEntityQuery(
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Class<?> cls,
|
Class<?> cls,
|
||||||
boolean selectEntitiesOnly,
|
boolean selectEntitiesOnly,
|
||||||
boolean selectDeletedEntities) {
|
boolean selectDeletedEntities,
|
||||||
|
boolean selectRevisionInfoOnly) {
|
||||||
super( enversService, versionsReader, cls );
|
super( enversService, versionsReader, cls );
|
||||||
|
|
||||||
this.selectEntitiesOnly = selectEntitiesOnly;
|
this.selectEntitiesOnly = selectEntitiesOnly;
|
||||||
this.selectDeletedEntities = selectDeletedEntities;
|
this.selectDeletedEntities = selectDeletedEntities;
|
||||||
|
this.selectRevisionInfoOnly = selectRevisionInfoOnly && !selectEntitiesOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RevisionsOfEntityQuery(
|
public RevisionsOfEntityQuery(
|
||||||
|
@ -48,11 +52,13 @@ public class RevisionsOfEntityQuery extends AbstractAuditQuery {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Class<?> cls, String entityName,
|
Class<?> cls, String entityName,
|
||||||
boolean selectEntitiesOnly,
|
boolean selectEntitiesOnly,
|
||||||
boolean selectDeletedEntities) {
|
boolean selectDeletedEntities,
|
||||||
|
boolean selectRevisionInfoOnly) {
|
||||||
super( enversService, versionsReader, cls, entityName );
|
super( enversService, versionsReader, cls, entityName );
|
||||||
|
|
||||||
this.selectEntitiesOnly = selectEntitiesOnly;
|
this.selectEntitiesOnly = selectEntitiesOnly;
|
||||||
this.selectDeletedEntities = selectDeletedEntities;
|
this.selectDeletedEntities = selectDeletedEntities;
|
||||||
|
this.selectRevisionInfoOnly = selectRevisionInfoOnly && !selectEntitiesOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Number getRevisionNumber(Map versionsEntity) {
|
private Number getRevisionNumber(Map versionsEntity) {
|
||||||
|
@ -121,6 +127,9 @@ public class RevisionsOfEntityQuery extends AbstractAuditQuery {
|
||||||
if ( hasProjection() ) {
|
if ( hasProjection() ) {
|
||||||
return queryResult;
|
return queryResult;
|
||||||
}
|
}
|
||||||
|
else if ( selectRevisionInfoOnly ) {
|
||||||
|
return queryResult.stream().map( e -> ( (Object[]) e )[1] ).collect( Collectors.toList() );
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
List entities = new ArrayList();
|
List entities = new ArrayList();
|
||||||
String revisionTypePropertyName = verEntCfg.getRevisionTypePropName();
|
String revisionTypePropertyName = verEntCfg.getRevisionTypePropName();
|
||||||
|
|
|
@ -7,14 +7,23 @@
|
||||||
package org.hibernate.envers.test.integration.auditReader;
|
package org.hibernate.envers.test.integration.auditReader;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.hibernate.envers.enhanced.SequenceIdRevisionEntity;
|
||||||
import org.hibernate.envers.exception.NotAuditedException;
|
import org.hibernate.envers.exception.NotAuditedException;
|
||||||
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
|
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
|
||||||
import org.hibernate.envers.test.Priority;
|
import org.hibernate.envers.test.Priority;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A test which checks the correct behavior of AuditReader.isEntityClassAudited(Class entityClass).
|
* A test which checks the correct behavior of AuditReader.isEntityClassAudited(Class entityClass).
|
||||||
*
|
*
|
||||||
|
@ -45,13 +54,17 @@ public class AuditReaderAPITest extends BaseEnversJPAFunctionalTestCase {
|
||||||
ent1.setStr1( "str2" );
|
ent1.setStr1( "str2" );
|
||||||
ent2.setStr1( "str2" );
|
ent2.setStr1( "str2" );
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
ent1 = em.find( AuditedTestEntity.class, 1 );
|
||||||
|
em.remove( ent1 );
|
||||||
|
em.getTransaction().commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsEntityClassAuditedForAuditedEntity() {
|
public void testIsEntityClassAuditedForAuditedEntity() {
|
||||||
assert getAuditReader().isEntityClassAudited( AuditedTestEntity.class );
|
assertTrue( getAuditReader().isEntityClassAudited( AuditedTestEntity.class ) );
|
||||||
|
assertEquals( Arrays.asList( 1, 2, 3 ), getAuditReader().getRevisions( AuditedTestEntity.class, 1 ) );
|
||||||
assert Arrays.asList( 1, 2 ).equals( getAuditReader().getRevisions( AuditedTestEntity.class, 1 ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -68,5 +81,37 @@ public class AuditReaderAPITest extends BaseEnversJPAFunctionalTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-7555" )
|
||||||
|
public void testFindRevisionEntitiesWithoutDeletions() {
|
||||||
|
List<?> revisionInfos = getAuditReader().createQuery()
|
||||||
|
.forRevisionsOfEntity( AuditedTestEntity.class, false )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 2, revisionInfos.size() );
|
||||||
|
revisionInfos.forEach( e -> assertTyping( SequenceIdRevisionEntity.class, e ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-7555" )
|
||||||
|
public void testFindRevisionEntitiesWithDeletions() {
|
||||||
|
List<?> revisionInfos = getAuditReader().createQuery()
|
||||||
|
.forRevisionsOfEntity( AuditedTestEntity.class, true )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 3, revisionInfos.size() );
|
||||||
|
revisionInfos.forEach( e -> assertTyping( SequenceIdRevisionEntity.class, e ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-7555" )
|
||||||
|
public void testFindRevisionEntitiesNonAuditedEntity() {
|
||||||
|
try {
|
||||||
|
List<?> revisionInfos = getAuditReader().createQuery()
|
||||||
|
.forRevisionsOfEntity( NotAuditedTestEntity.class, false )
|
||||||
|
.getResultList();
|
||||||
|
fail( "Expected a NotAuditedException" );
|
||||||
|
}
|
||||||
|
catch ( NotAuditedException e ) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue