HHH-13780 Allow NamedQuery to set hint QueryHints.PASS_DISTINCT_THROUGH
This commit is contained in:
parent
63a96e335e
commit
bf473681e4
|
@ -67,6 +67,7 @@ public abstract class QueryBinder {
|
|||
.setReadOnly( hints.getBoolean( queryName, QueryHints.READ_ONLY ) )
|
||||
.setComment( hints.getString( queryName, QueryHints.COMMENT ) )
|
||||
.setParameterTypes( null )
|
||||
.setPassDistinctThrough( hints.getPassDistinctThrough( queryName ) )
|
||||
.createNamedQueryDefinition();
|
||||
|
||||
if ( isDefault ) {
|
||||
|
@ -108,8 +109,9 @@ public abstract class QueryBinder {
|
|||
.setReadOnly( hints.getBoolean( queryName, QueryHints.READ_ONLY ) )
|
||||
.setComment( hints.getString( queryName, QueryHints.COMMENT ) )
|
||||
.setParameterTypes( null )
|
||||
.setCallable( hints.getBoolean( queryName, QueryHints.CALLABLE ) );
|
||||
|
||||
.setCallable( hints.getBoolean( queryName, QueryHints.CALLABLE ) )
|
||||
.setPassDistinctThrough( hints.getPassDistinctThrough( queryName ) );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( resultSetMapping ) ) {
|
||||
//sql result set usage
|
||||
builder.setResultSetRef( resultSetMapping )
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.cfg.annotations;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.QueryHint;
|
||||
|
@ -84,21 +85,28 @@ public class QueryHintDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
public Boolean getPassDistinctThrough(String query) {
|
||||
return doGetBoolean( query, QueryHints.PASS_DISTINCT_THROUGH ).orElse( null );
|
||||
}
|
||||
|
||||
public boolean getBoolean(String query, String hintName) {
|
||||
String value =(String) hintsMap.get( hintName );
|
||||
return doGetBoolean( query, hintName ).orElse( false );
|
||||
}
|
||||
|
||||
private Optional<Boolean> doGetBoolean(String query, String hintName) {
|
||||
String value = (String) hintsMap.get( hintName );
|
||||
if ( value == null ) {
|
||||
return false;
|
||||
return Optional.empty();
|
||||
}
|
||||
if ( value.equalsIgnoreCase( "true" ) ) {
|
||||
return true;
|
||||
return Optional.of( true );
|
||||
}
|
||||
else if ( value.equalsIgnoreCase( "false" ) ) {
|
||||
return false;
|
||||
return Optional.of( false );
|
||||
}
|
||||
else {
|
||||
throw new AnnotationException( "Not a boolean in hint: " + query + ":" + hintName );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getString(String query, String hintName) {
|
||||
|
|
|
@ -33,6 +33,7 @@ public class NamedQueryDefinition implements Serializable {
|
|||
private final CacheMode cacheMode;
|
||||
private final boolean readOnly;
|
||||
private final String comment;
|
||||
private final Boolean passDistinctThrough;
|
||||
|
||||
// added for jpa 2.1
|
||||
private final Integer firstResult;
|
||||
|
@ -133,7 +134,8 @@ public class NamedQueryDefinition implements Serializable {
|
|||
comment,
|
||||
parameterTypes,
|
||||
null, // firstResult
|
||||
null // maxResults
|
||||
null, // maxResults
|
||||
null // passDistinctThrough
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -151,7 +153,8 @@ public class NamedQueryDefinition implements Serializable {
|
|||
String comment,
|
||||
Map parameterTypes,
|
||||
Integer firstResult,
|
||||
Integer maxResults) {
|
||||
Integer maxResults,
|
||||
Boolean passDistinctThrough) {
|
||||
this.name = name;
|
||||
this.query = query;
|
||||
this.cacheable = cacheable;
|
||||
|
@ -167,6 +170,7 @@ public class NamedQueryDefinition implements Serializable {
|
|||
|
||||
this.firstResult = firstResult;
|
||||
this.maxResults = maxResults;
|
||||
this.passDistinctThrough = passDistinctThrough;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
@ -230,6 +234,10 @@ public class NamedQueryDefinition implements Serializable {
|
|||
return maxResults;
|
||||
}
|
||||
|
||||
public Boolean getPassDistinctThrough() {
|
||||
return passDistinctThrough;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + '(' + name + " [" + query + "])";
|
||||
|
@ -250,7 +258,8 @@ public class NamedQueryDefinition implements Serializable {
|
|||
getComment(),
|
||||
getParameterTypes(),
|
||||
getFirstResult(),
|
||||
getMaxResults()
|
||||
getMaxResults(),
|
||||
getPassDistinctThrough()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public class NamedQueryDefinitionBuilder {
|
|||
protected LockOptions lockOptions;
|
||||
protected Integer firstResult;
|
||||
protected Integer maxResults;
|
||||
protected Boolean passDistinctThrough;
|
||||
|
||||
public NamedQueryDefinitionBuilder() {
|
||||
}
|
||||
|
@ -114,6 +115,11 @@ public class NamedQueryDefinitionBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public NamedQueryDefinitionBuilder setPassDistinctThrough(Boolean passDistinctThrough) {
|
||||
this.passDistinctThrough = passDistinctThrough;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NamedQueryDefinition createNamedQueryDefinition() {
|
||||
return new NamedQueryDefinition(
|
||||
name,
|
||||
|
@ -129,7 +135,8 @@ public class NamedQueryDefinitionBuilder {
|
|||
comment,
|
||||
parameterTypes,
|
||||
firstResult,
|
||||
maxResults
|
||||
maxResults,
|
||||
passDistinctThrough
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition {
|
|||
null, // resultSetRef
|
||||
querySpaces,
|
||||
callable,
|
||||
queryReturns
|
||||
queryReturns,
|
||||
null // passDistinctThrough
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -140,7 +141,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition {
|
|||
resultSetRef,
|
||||
querySpaces,
|
||||
callable,
|
||||
null // queryReturns
|
||||
null, // queryReturns
|
||||
null // passDistinctThrough
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -161,7 +163,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition {
|
|||
String resultSetRef,
|
||||
List<String> querySpaces,
|
||||
boolean callable,
|
||||
NativeSQLQueryReturn[] queryReturns) {
|
||||
NativeSQLQueryReturn[] queryReturns,
|
||||
Boolean passDistinctThrough) {
|
||||
super(
|
||||
name,
|
||||
query.trim(), /* trim done to workaround stupid oracle bug that cant handle whitespaces before a { in a sp */
|
||||
|
@ -176,7 +179,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition {
|
|||
comment,
|
||||
parameterTypes,
|
||||
firstResult,
|
||||
maxResults
|
||||
maxResults,
|
||||
passDistinctThrough
|
||||
);
|
||||
this.resultSetRef = resultSetRef;
|
||||
this.querySpaces = querySpaces;
|
||||
|
@ -219,7 +223,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition {
|
|||
getResultSetRef(),
|
||||
getQuerySpaces(),
|
||||
isCallable(),
|
||||
getQueryReturns()
|
||||
getQueryReturns(),
|
||||
getPassDistinctThrough()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,11 @@ public class NamedSQLQueryDefinitionBuilder extends NamedQueryDefinitionBuilder
|
|||
return (NamedSQLQueryDefinitionBuilder) super.setMaxResults( maxResults );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedSQLQueryDefinitionBuilder setPassDistinctThrough(Boolean passDistinctThrough) {
|
||||
return (NamedSQLQueryDefinitionBuilder) super.setPassDistinctThrough( passDistinctThrough );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedSQLQueryDefinition createNamedQueryDefinition() {
|
||||
return new NamedSQLQueryDefinition(
|
||||
|
@ -168,7 +173,8 @@ public class NamedSQLQueryDefinitionBuilder extends NamedQueryDefinitionBuilder
|
|||
resultSetRef,
|
||||
querySpacesCopy(),
|
||||
callable,
|
||||
queryReturns
|
||||
queryReturns,
|
||||
passDistinctThrough
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
import org.hibernate.engine.transaction.internal.TransactionImpl;
|
||||
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
||||
import org.hibernate.id.uuid.StandardRandomStrategy;
|
||||
import org.hibernate.jpa.QueryHints;
|
||||
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
|
||||
import org.hibernate.jpa.spi.CriteriaQueryTupleTransformer;
|
||||
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
|
||||
|
@ -695,6 +696,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
if ( nqd.getFlushMode() != null ) {
|
||||
query.setHibernateFlushMode( nqd.getFlushMode() );
|
||||
}
|
||||
if ( nqd.getPassDistinctThrough() != null ) {
|
||||
query.setHint( QueryHints.HINT_PASS_DISTINCT_THROUGH, nqd.getPassDistinctThrough() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,6 +14,9 @@ import javax.persistence.Entity;
|
|||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.QueryHint;
|
||||
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.jpa.QueryHints;
|
||||
|
@ -34,6 +37,9 @@ import static org.junit.Assert.assertTrue;
|
|||
@TestForIssue( jiraKey = "HHH-10965" )
|
||||
public class SelectDistinctHqlTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private static final String DISTINCT_PASSES_THROUGH_TRUE_NAMED_QUERY = "distinctPassesThroughTrue";
|
||||
private static final String DISTINCT_PASSES_THROUGH_FALSE_NAMED_QUERY = "distinctPassesThroughFalse";
|
||||
private static final String DISTINCT_PASSES_THROUGH_NOT_SPECIFIED_NAMED_QUERY = "distinctPassesThroughNotSpecified";
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
|
@ -137,7 +143,65 @@ public class SelectDistinctHqlTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13780")
|
||||
public void testNamedQueryDistinctPassThroughTrue() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
sqlStatementInterceptor.getSqlQueries().clear();
|
||||
List<Person> persons = session.createNamedQuery( DISTINCT_PASSES_THROUGH_TRUE_NAMED_QUERY, Person.class )
|
||||
.setMaxResults( 5 )
|
||||
.getResultList();
|
||||
assertEquals( 1, persons.size() );
|
||||
String sqlQuery = sqlStatementInterceptor.getSqlQueries().getLast();
|
||||
assertTrue( sqlQuery.contains( " distinct " ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13780")
|
||||
public void testNamedQueryDistinctPassThroughTrueWhenNotSpecified() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
sqlStatementInterceptor.getSqlQueries().clear();
|
||||
List<Person> persons =
|
||||
session.createNamedQuery( DISTINCT_PASSES_THROUGH_NOT_SPECIFIED_NAMED_QUERY, Person.class )
|
||||
.setMaxResults( 5 )
|
||||
.getResultList();
|
||||
assertEquals( 1, persons.size() );
|
||||
String sqlQuery = sqlStatementInterceptor.getSqlQueries().getLast();
|
||||
assertTrue( sqlQuery.contains( " distinct " ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13780")
|
||||
public void testNamedQueryDistinctPassThroughFalse() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
sqlStatementInterceptor.getSqlQueries().clear();
|
||||
List<Person> persons =
|
||||
session.createNamedQuery( DISTINCT_PASSES_THROUGH_FALSE_NAMED_QUERY, Person.class )
|
||||
.setMaxResults( 5 )
|
||||
.getResultList();
|
||||
assertEquals( 1, persons.size() );
|
||||
String sqlQuery = sqlStatementInterceptor.getSqlQueries().getLast();
|
||||
assertFalse( sqlQuery.contains( " distinct " ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = DISTINCT_PASSES_THROUGH_TRUE_NAMED_QUERY,
|
||||
query = "select distinct p from Person p left join fetch p.phones",
|
||||
hints = {
|
||||
@QueryHint(name = QueryHints.HINT_PASS_DISTINCT_THROUGH, value = "true")
|
||||
}),
|
||||
@NamedQuery(name = DISTINCT_PASSES_THROUGH_FALSE_NAMED_QUERY,
|
||||
query = "select distinct p from Person p left join fetch p.phones",
|
||||
hints = {
|
||||
@QueryHint(name = QueryHints.HINT_PASS_DISTINCT_THROUGH, value = "false")
|
||||
}),
|
||||
@NamedQuery(name = DISTINCT_PASSES_THROUGH_NOT_SPECIFIED_NAMED_QUERY,
|
||||
query = "select distinct p from Person p left join fetch p.phones")
|
||||
})
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
|
|
Loading…
Reference in New Issue