diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/id/AbstractIdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/id/AbstractIdMapper.java index 9b839ce49f..3e1a7eefcf 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/id/AbstractIdMapper.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/id/AbstractIdMapper.java @@ -60,7 +60,7 @@ public abstract class AbstractIdMapper implements IdMapper { QueryParameterData paramData1 = paramDataIter1.next(); QueryParameterData paramData2 = paramDataIter2.next(); - parametersToUse.addWhere(paramData1.getProperty(prefix1), false, "=", paramData2.getProperty(prefix2), false); + parametersToUse.addWhere(paramData1.getProperty(prefix1), false, "=", paramData2.getProperty(prefix2), false); } } @@ -70,7 +70,11 @@ public abstract class AbstractIdMapper implements IdMapper { Parameters parametersToUse = getParametersToUse(parameters, paramDatas); for (QueryParameterData paramData : paramDatas) { - parametersToUse.addWhereWithParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getValue()); + if (paramData.getValue() == null) { + handleNullValue(parametersToUse, paramData.getProperty(prefix), equals); + } else { + parametersToUse.addWhereWithParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getValue()); + } } } @@ -83,4 +87,12 @@ public abstract class AbstractIdMapper implements IdMapper { parametersToUse.addWhereWithNamedParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getQueryParameterName()); } } + + private void handleNullValue(Parameters parameters, String propertyName, boolean equals) { + if (equals) { + parameters.addNullRestriction(propertyName, equals); + } else { + parameters.addNotNullRestriction(propertyName, equals); + } + } } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/NotNullAuditExpression.java b/hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/NotNullAuditExpression.java index 5bc01b57f5..986d0152bd 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/NotNullAuditExpression.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/NotNullAuditExpression.java @@ -24,10 +24,13 @@ package org.hibernate.envers.query.criteria; import org.hibernate.envers.configuration.AuditConfiguration; import org.hibernate.envers.entities.RelationDescription; +import org.hibernate.envers.entities.mapper.id.QueryParameterData; import org.hibernate.envers.query.property.PropertyNameGetter; import org.hibernate.envers.tools.query.Parameters; import org.hibernate.envers.tools.query.QueryBuilder; +import java.util.List; + /** * @author Adam Warski (adam at warski dot org) */ @@ -43,7 +46,7 @@ public class NotNullAuditExpression implements AuditCriterion { RelationDescription relatedEntity = CriteriaTools.getRelatedEntity(auditCfg, entityName, propertyName); if (relatedEntity == null) { - parameters.addWhereWithParam(propertyName, "<>", null); + parameters.addNotNullRestriction(propertyName, true); } else { relatedEntity.getIdMapper().addIdEqualsToQuery(parameters, null, propertyName, false); } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/NullAuditExpression.java b/hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/NullAuditExpression.java index 77deec22ef..4565256c43 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/NullAuditExpression.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/NullAuditExpression.java @@ -43,7 +43,7 @@ public class NullAuditExpression implements AuditCriterion { RelationDescription relatedEntity = CriteriaTools.getRelatedEntity(auditCfg, entityName, propertyName); if (relatedEntity == null) { - parameters.addWhereWithParam(propertyName, "=", null); + parameters.addNullRestriction(propertyName, true); } else { relatedEntity.getIdMapper().addIdEqualsToQuery(parameters, null, propertyName, true); } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/tools/query/Parameters.java b/hibernate-envers/src/main/java/org/hibernate/envers/tools/query/Parameters.java index 5d63f1839e..e747dbd347 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/tools/query/Parameters.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/tools/query/Parameters.java @@ -114,6 +114,24 @@ public class Parameters { addWhere(left, true, op, right, true); } + /** + * Adds IS NULL restriction. + * @param propertyName Property name. + * @param addAlias Positive if alias to property name shall be added. + */ + public void addNullRestriction(String propertyName, boolean addAlias) { + addWhere(propertyName, addAlias, "is", "null", false); + } + + /** + * Adds IS NOT NULL restriction. + * @param propertyName Property name. + * @param addAlias Positive if alias to property name shall be added. + */ + public void addNotNullRestriction(String propertyName, boolean addAlias) { + addWhere(propertyName, addAlias, "is not", "null", false); + } + public void addWhere(String left, boolean addAliasLeft, String op, String right, boolean addAliasRight) { StringBuilder expression = new StringBuilder(); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/query/NullPropertyQuery.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/query/NullPropertyQuery.java new file mode 100644 index 0000000000..91f9592877 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/query/NullPropertyQuery.java @@ -0,0 +1,103 @@ +package org.hibernate.envers.test.integration.query; + +import org.hibernate.ejb.Ejb3Configuration; +import org.hibernate.envers.query.AuditEntity; +import org.hibernate.envers.test.AbstractEntityTest; +import org.hibernate.envers.test.Priority; +import org.hibernate.envers.test.entities.StrIntTestEntity; +import org.hibernate.envers.test.entities.ids.EmbId; +import org.hibernate.envers.test.entities.onetomany.CollectionRefEdEntity; +import org.hibernate.envers.test.entities.onetomany.CollectionRefIngEntity; +import org.hibernate.envers.test.entities.onetomany.ids.SetRefEdEmbIdEntity; +import org.hibernate.envers.test.entities.onetomany.ids.SetRefIngEmbIdEntity; +import org.junit.Test; + +import javax.persistence.EntityManager; + +/** + * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) + */ +public class NullPropertyQuery extends AbstractEntityTest { + private Integer idSimplePropertyNull = null; + private Integer idSimplePropertyNotNull = null; + private EmbId idMulticolumnReferenceToParentNull = new EmbId(0, 1); + private Integer idReferenceToParentNotNull = 1; + private Integer idParent = 1; + + public void configure(Ejb3Configuration cfg) { + cfg.addAnnotatedClass(StrIntTestEntity.class); + cfg.addAnnotatedClass(SetRefEdEmbIdEntity.class); + cfg.addAnnotatedClass(SetRefIngEmbIdEntity.class); + cfg.addAnnotatedClass(CollectionRefEdEntity.class); + cfg.addAnnotatedClass(CollectionRefIngEntity.class); + } + + @Test + @Priority(10) + public void initData() { + // Revision 1 + EntityManager em = getEntityManager(); + em.getTransaction().begin(); + StrIntTestEntity nullSite = new StrIntTestEntity(null, 1); + StrIntTestEntity notNullSite = new StrIntTestEntity("data", 2); + em.persist(nullSite); + em.persist(notNullSite); + idSimplePropertyNull = nullSite.getId(); + idSimplePropertyNotNull = notNullSite.getId(); + em.getTransaction().commit(); + + // Revision 2 + em.getTransaction().begin(); + SetRefIngEmbIdEntity nullParentSrieie = new SetRefIngEmbIdEntity(idMulticolumnReferenceToParentNull, "data", null); + em.persist(nullParentSrieie); + em.getTransaction().commit(); + + // Revision 3 + em.getTransaction().begin(); + CollectionRefEdEntity parent = new CollectionRefEdEntity(idParent, "data"); + CollectionRefIngEntity notNullParentCrie = new CollectionRefIngEntity(idReferenceToParentNotNull, "data", parent); + em.persist(parent); + em.persist(notNullParentCrie); + em.getTransaction().commit(); + } + + @Test + public void testSimplePropertyIsNullQuery() { + StrIntTestEntity ver = (StrIntTestEntity) getAuditReader().createQuery() + .forEntitiesAtRevision(StrIntTestEntity.class, 1) + .add(AuditEntity.property("str1").isNull()) + .getSingleResult(); + + assert ver.equals(new StrIntTestEntity(null, 1, idSimplePropertyNull)); + } + + @Test + public void testSimplePropertyIsNotNullQuery() { + StrIntTestEntity ver = (StrIntTestEntity) getAuditReader().createQuery() + .forEntitiesAtRevision(StrIntTestEntity.class, 1) + .add(AuditEntity.property("str1").isNotNull()) + .getSingleResult(); + + assert ver.equals(new StrIntTestEntity("data", 2, idSimplePropertyNotNull)); + } + + @Test + public void testReferenceMulticolumnPropertyIsNullQuery() { + SetRefIngEmbIdEntity ver = (SetRefIngEmbIdEntity) getAuditReader().createQuery() + .forEntitiesAtRevision(SetRefIngEmbIdEntity.class, 2) + .add(AuditEntity.property("reference").isNull()) + .getSingleResult(); + + assert ver.getId().equals(idMulticolumnReferenceToParentNull); + } + + @Test + public void testReferencePropertyIsNotNullQuery() { + CollectionRefIngEntity ver = (CollectionRefIngEntity) getAuditReader().createQuery() + .forEntitiesAtRevision(CollectionRefIngEntity.class, 3) + .add(AuditEntity.property("reference").isNotNull()) + .getSingleResult(); + + assert ver.getId().equals(idReferenceToParentNotNull); + } +} \ No newline at end of file