Fix native named query max results

This commit is contained in:
Andrea Boriero 2022-02-08 18:51:52 +01:00 committed by Andrea Boriero
parent 74e1e6caad
commit 07f3d6727f
6 changed files with 146 additions and 10 deletions

View File

@ -27,6 +27,8 @@ public class NamedNativeQueryDefinitionImpl extends AbstractNamedQueryDefinition
private final String resultSetMappingName; private final String resultSetMappingName;
private final String resultSetMappingClassName; private final String resultSetMappingClassName;
private final Set<String> querySpaces; private final Set<String> querySpaces;
private Integer firstResult;
private Integer maxResults;
public NamedNativeQueryDefinitionImpl( public NamedNativeQueryDefinitionImpl(
String name, String name,
@ -42,6 +44,8 @@ public class NamedNativeQueryDefinitionImpl extends AbstractNamedQueryDefinition
Integer timeout, Integer timeout,
Integer fetchSize, Integer fetchSize,
String comment, String comment,
Integer firstResult,
Integer maxResults,
Map<String,Object> hints) { Map<String,Object> hints) {
super( super(
name, name,
@ -60,6 +64,8 @@ public class NamedNativeQueryDefinitionImpl extends AbstractNamedQueryDefinition
this.resultSetMappingName = resultSetMappingName; this.resultSetMappingName = resultSetMappingName;
this.resultSetMappingClassName = resultSetMappingClassName; this.resultSetMappingClassName = resultSetMappingClassName;
this.querySpaces = querySpaces; this.querySpaces = querySpaces;
this.firstResult = firstResult;
this.maxResults = maxResults;
} }
@Override @Override
@ -97,6 +103,8 @@ public class NamedNativeQueryDefinitionImpl extends AbstractNamedQueryDefinition
getTimeout(), getTimeout(),
getFetchSize(), getFetchSize(),
getComment(), getComment(),
firstResult,
maxResults,
getHints() getHints()
); );
} }

View File

@ -28,6 +28,8 @@ public class NamedNativeQueryDefinitionBuilder extends AbstractNamedQueryBuilder
private Set<String> querySpaces; private Set<String> querySpaces;
private Map<String, String> parameterTypes; private Map<String, String> parameterTypes;
private Integer firstResult;
private Integer maxResults;
public NamedNativeQueryDefinitionBuilder(String name) { public NamedNativeQueryDefinitionBuilder(String name) {
super( name ); super( name );
@ -38,6 +40,16 @@ public class NamedNativeQueryDefinitionBuilder extends AbstractNamedQueryBuilder
return getThis(); return getThis();
} }
public NamedNativeQueryDefinitionBuilder setFirstResult(Integer firstResult) {
this.firstResult = firstResult;
return getThis();
}
public NamedNativeQueryDefinitionBuilder setMaxResults(Integer maxResults) {
this.maxResults = maxResults;
return getThis();
}
public NamedNativeQueryDefinition build() { public NamedNativeQueryDefinition build() {
return new NamedNativeQueryDefinitionImpl( return new NamedNativeQueryDefinitionImpl(
getName(), getName(),
@ -53,6 +65,8 @@ public class NamedNativeQueryDefinitionBuilder extends AbstractNamedQueryBuilder
getTimeout(), getTimeout(),
getFetchSize(), getFetchSize(),
getComment(), getComment(),
firstResult,
maxResults,
getHints() getHints()
); );
} }

View File

@ -14,7 +14,6 @@ import org.hibernate.FlushMode;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.named.AbstractNamedQueryMemento; import org.hibernate.query.named.AbstractNamedQueryMemento;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.sql.spi.NamedNativeQueryMemento; import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
import org.hibernate.query.sql.spi.NativeQueryImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor;
@ -32,6 +31,10 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
private final Set<String> querySpaces; private final Set<String> querySpaces;
private final Integer firstResult;
private final Integer maxResults;
public NamedNativeQueryMementoImpl( public NamedNativeQueryMementoImpl(
String name, String name,
String sqlString, String sqlString,
@ -46,6 +49,8 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
Integer timeout, Integer timeout,
Integer fetchSize, Integer fetchSize,
String comment, String comment,
Integer firstResult,
Integer maxResults,
Map<String,Object> hints) { Map<String,Object> hints) {
super( super(
name, name,
@ -65,6 +70,8 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
: resultSetMappingName; : resultSetMappingName;
this.resultSetMappingClass = resultSetMappingClass; this.resultSetMappingClass = resultSetMappingClass;
this.querySpaces = querySpaces; this.querySpaces = querySpaces;
this.firstResult = firstResult;
this.maxResults = maxResults;
} }
public String getResultSetMappingName() { public String getResultSetMappingName() {
@ -94,6 +101,16 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
return resultSetMappingClass; return resultSetMappingClass;
} }
@Override
public Integer getFirstResult() {
return firstResult;
}
@Override
public Integer getMaxResults() {
return maxResults;
}
@Override @Override
public NamedNativeQueryMemento makeCopy(String name) { public NamedNativeQueryMemento makeCopy(String name) {
return new NamedNativeQueryMementoImpl( return new NamedNativeQueryMementoImpl(
@ -110,6 +127,8 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
getTimeout(), getTimeout(),
getFetchSize(), getFetchSize(),
getComment(), getComment(),
getFirstResult(),
getMaxResults(),
getHints() getHints()
); );
} }

View File

@ -360,6 +360,13 @@ public class NativeQueryImpl<R>
protected void applyOptions(NamedNativeQueryMemento memento) { protected void applyOptions(NamedNativeQueryMemento memento) {
super.applyOptions( memento ); super.applyOptions( memento );
if ( memento.getMaxResults() != null ) {
setMaxResults( memento.getMaxResults() );
}
if ( memento.getFirstResult() != null ) {
setFirstResult( memento.getFirstResult() );
}
final Set<String> copy = CollectionHelper.makeCopy( memento.getQuerySpaces() ); final Set<String> copy = CollectionHelper.makeCopy( memento.getQuerySpaces() );
if ( copy != null ) { if ( copy != null ) {
this.querySpaces = copy; this.querySpaces = copy;
@ -457,8 +464,9 @@ public class NativeQueryImpl<R>
getTimeout(), getTimeout(),
getFetchSize(), getFetchSize(),
getComment(), getComment(),
getFirstResult(),
getMaxResults(),
getHints() getHints()
); );
} }

View File

@ -47,6 +47,10 @@ public interface NamedNativeQueryMemento extends NamedQueryMemento {
*/ */
Class<?> getResultMappingClass(); Class<?> getResultMappingClass();
Integer getFirstResult();
Integer getMaxResults();
/** /**
* Convert the memento into an untyped executable query * Convert the memento into an untyped executable query
*/ */
@ -142,6 +146,8 @@ public interface NamedNativeQueryMemento extends NamedQueryMemento {
timeout, timeout,
fetchSize, fetchSize,
comment, comment,
firstResult,
maxResults,
hints hints
); );
} }

View File

@ -9,42 +9,55 @@ package org.hibernate.orm.test.jpa.compliance;
import java.util.List; import java.util.List;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa; import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Query;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.Root;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@Jpa( @Jpa(
annotatedClasses = NamedQueryTest.Person.class annotatedClasses = NamedQueryTest.Person.class,
properties = @Setting(name = AvailableSettings.JPA_CRITERIA_COPY_COMPLIANCE, value = "true")
) )
public class NamedQueryTest { public class NamedQueryTest {
@BeforeEach @BeforeEach
public void setup(EntityManagerFactoryScope scope) { public void setup(EntityManagerFactoryScope scope) {
scope.inTransaction( scope.inTransaction(
entityManager -> { entityManager -> {
Person person1 = new Person( 1, "Andrea" ); entityManager.persist( new Person( 1, "Andrea" ) );
Person person2 = new Person( 2, "Alberto" ); entityManager.persist( new Person( 2, "Alberto" ) );
entityManager.persist( person1 );
entityManager.persist( person2 );
} }
); );
} }
@AfterEach
public void tearDown(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager ->
entityManager.createQuery( "delete from Person" ).executeUpdate()
);
}
@Test @Test
public void testNameQueryCreationFromCritera(EntityManagerFactoryScope scope) { public void testNameQueryCreationFromCriteria(EntityManagerFactoryScope scope) {
final EntityManagerFactory entityManagerFactory = scope.getEntityManagerFactory(); final EntityManagerFactory entityManagerFactory = scope.getEntityManagerFactory();
@ -68,6 +81,74 @@ public class NamedQueryTest {
} }
@Test
public void testNativeWithMaxResults(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
final Query nativeQuery = entityManager.createNativeQuery(
"Select p.id from PERSON_TABLE p" );
nativeQuery.setMaxResults( 1 );
scope.getEntityManagerFactory().addNamedQuery( "native", nativeQuery );
final Query namedQuery = entityManager.createNamedQuery( "native" );
assertEquals( 1, namedQuery.getMaxResults() );
namedQuery.setMaxResults( 2 );
assertEquals( 2, namedQuery.getMaxResults() );
final List<Integer> ids = namedQuery.getResultList();
assertEquals( 2, ids.size() );
assertThat( ids, hasItems( 1, 2 ) );
} );
}
@Test
public void testCriteriaWithMaxResults(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Integer> criteriaQuery = criteriaBuilder.createQuery( Integer.class );
final Root<Person> person = criteriaQuery.from( Person.class );
criteriaQuery.select( person.get( "id" ) );
criteriaQuery.orderBy( criteriaBuilder.asc( person.get( "id" ) ) );
final TypedQuery<Integer> typedQuery = entityManager.createQuery( criteriaQuery );
typedQuery.setMaxResults( 1 );
scope.getEntityManagerFactory().addNamedQuery( "criteria", typedQuery );
final Query namedQuery = entityManager.createNamedQuery( "criteria" );
assertEquals( 1, namedQuery.getMaxResults() );
namedQuery.setMaxResults( 2 );
assertEquals( 2, namedQuery.getMaxResults() );
final List<Integer> ids = namedQuery.getResultList();
assertEquals( 2, ids.size() );
assertThat( ids, hasItems( 1, 2 ) );
} );
}
@Test
public void testHqlWithMaxResults(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
final Query query = entityManager.createQuery( "Select p.id from Person p" );
query.setMaxResults( 1 );
scope.getEntityManagerFactory().addNamedQuery( "query", query );
final Query namedQuery = entityManager.createNamedQuery( "query" );
assertEquals( 1, namedQuery.getMaxResults() );
namedQuery.setMaxResults( 2 );
assertEquals( 2, namedQuery.getMaxResults() );
final List<Integer> ids = namedQuery.getResultList();
assertEquals( 2, ids.size() );
assertThat( ids, hasItems( 1, 2 ) );
} );
}
@Entity(name = "Person") @Entity(name = "Person")
@Table(name = "PERSON_TABLE") @Table(name = "PERSON_TABLE")
public static class Person { public static class Person {