diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedStandard.java index 3dc5a58363aa..ffd03f3596a1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedStandard.java @@ -27,7 +27,7 @@ /** * ResultBuilder for scalar results defined via: * * @author Steve Ebersole @@ -60,7 +60,7 @@ public ResultBuilder cacheKeyInstance() { @Override public Class getJavaType() { - return explicitJavaType.getJavaTypeClass(); + return explicitJavaType == null ? null : explicitJavaType.getJavaTypeClass(); } @Override @@ -157,23 +157,14 @@ public boolean equals(Object o) { if ( o == null || getClass() != o.getClass() ) { return false; } - CompleteResultBuilderBasicValuedStandard that = (CompleteResultBuilderBasicValuedStandard) o; - - if ( !Objects.equals( explicitColumnName, that.explicitColumnName ) ) { - return false; - } - if ( !Objects.equals( explicitType, that.explicitType ) ) { - return false; - } - return explicitJavaType.equals( that.explicitJavaType ); + return Objects.equals( explicitColumnName, that.explicitColumnName ) + && Objects.equals( explicitType, that.explicitType ) + && Objects.equals( explicitJavaType, that.explicitJavaType ); } @Override public int hashCode() { - int result = explicitColumnName != null ? explicitColumnName.hashCode() : 0; - result = 31 * result + ( explicitType != null ? explicitType.hashCode() : 0 ); - result = 31 * result + explicitJavaType.hashCode(); - return result; + return Objects.hash( explicitColumnName, explicitType, explicitJavaType ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java index 3ec4fbadc85d..f2964773024c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java @@ -278,7 +278,7 @@ else if ( resultJavaType != null && resultJavaType != Object[].class ) { throw new IllegalArgumentException( "Named query exists but its result type is not compatible" ); case 1: final Class actualResultJavaType = resultSetMapping.getResultBuilders().get( 0 ).getJavaType(); - if ( !resultJavaType.isAssignableFrom( actualResultJavaType ) ) { + if ( actualResultJavaType != null && !resultJavaType.isAssignableFrom( actualResultJavaType ) ) { throw buildIncompatibleException( resultJavaType, actualResultJavaType ); } break; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/NamedNativeQueryWithCountColumnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/NamedNativeQueryWithCountColumnTest.java new file mode 100644 index 000000000000..4e50bf90bf58 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/NamedNativeQueryWithCountColumnTest.java @@ -0,0 +1,105 @@ +/* + * 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.orm.test.query.resultmapping; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.H2Dialect; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.ColumnResult; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedNativeQuery; +import jakarta.persistence.SqlResultSetMapping; +import jakarta.persistence.Table; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Nathan Xu + */ +@Jpa( + annotatedClasses = NamedNativeQueryWithCountColumnTest.Sample.class, + properties = @Setting(name = AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, value = "true") +) +@TestForIssue(jiraKey = "HHH-15070") +class NamedNativeQueryWithCountColumnTest { + + @BeforeEach + public void setUp(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + for ( int i = 0; i < 3; i++ ) { + Sample sample = new Sample( i, String.valueOf( i ) ); + entityManager.persist( sample ); + } + } + ); + } + + @AfterEach + public void tearDown(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> + entityManager.createQuery( "delete from Sample" ).executeUpdate() + ); + } + + @Test + void testNamedNativeQuery(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> + entityManager.createNamedQuery( "sample.count", Long.class ) + ); + } + + @Test + @RequiresDialect(H2Dialect.class) + void testNamedNativeQueryExecution(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + Long count = entityManager.createNamedQuery( "sample.count", Long.class ).getSingleResult(); + assertThat( count, is( 3L ) ); + } ); + } + + @SqlResultSetMapping( + name = "mapping", + columns = @ColumnResult(name = "cnt") + ) + @NamedNativeQuery( + name = "sample.count", + resultSetMapping = "mapping", + query = "SELECT count(*) AS cnt FROM SAMPLE_TABLE" + ) + @Entity(name = "Sample") + @Table(name = "SAMPLE_TABLE") + static class Sample { + + @Id + Integer id; + + String name; + + public Sample() { + } + + public Sample(Integer id, String name) { + this.id = id; + this.name = name; + } + } +}