diff --git a/hibernate-core/src/main/java/org/hibernate/query/Query.java b/hibernate-core/src/main/java/org/hibernate/query/Query.java index 1d3c30d5a0..853054c85b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -160,15 +160,14 @@ public interface Query extends TypedQuery, CommonQueryContract { /** * Convenience method to return a single instance that matches - * the query, or {@code null} if the query returns no results. + * the query, throwing an exception if the query returns no results. * - * @return the single result or null + * @return the single result * - * @throws NonUniqueResultException if there is more than one matching result + * @throws jakarta.persistence.NonUniqueResultException if there is more than one matching result + * @throws jakarta.persistence.NoResultException if there is no result to return */ - default R getSingleResult() { - return uniqueResult(); - } + R getSingleResult(); /** * Convenience method to return a single instance that matches diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java index 31cda2d62e..aecbca5a64 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java @@ -1487,7 +1487,7 @@ public abstract class AbstractQuery implements QueryImplementor { public R getSingleResult() { try { final List list = list(); - if ( list.size() == 0 ) { + if ( list.isEmpty() ) { throw new NoResultException( "No entity found for query" ); } return uniqueElement( list ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/exceptionhandling/ExceptionExpectations.java b/hibernate-core/src/test/java/org/hibernate/orm/test/exceptionhandling/ExceptionExpectations.java index d60e10901d..90f2bb9854 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/exceptionhandling/ExceptionExpectations.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/exceptionhandling/ExceptionExpectations.java @@ -55,6 +55,11 @@ interface ExceptionExpectations { assertThat( e.getCause(), instanceOf( SemanticException.class ) ); } + @Override + public void onUniqueResultWithMultipleResults(RuntimeException e) { + assertThat( e, instanceOf( org.hibernate.NonUniqueResultException.class ) ); + } + @Override public void onGetSingleResultWithMultipleResults(RuntimeException e) { assertThat( e, instanceOf( jakarta.persistence.NonUniqueResultException.class ) ); @@ -133,6 +138,11 @@ interface ExceptionExpectations { assertThat( e, instanceOf( SemanticException.class ) ); } + @Override + public void onUniqueResultWithMultipleResults(RuntimeException e) { + assertThat( e, instanceOf( org.hibernate.NonUniqueResultException.class ) ); + } + @Override public void onGetSingleResultWithMultipleResults(RuntimeException e) { assertThat( e, instanceOf( org.hibernate.NonUniqueResultException.class ) ); @@ -208,6 +218,11 @@ interface ExceptionExpectations { assertThat( e.getCause(), instanceOf( SemanticException.class ) ); } + @Override + public void onUniqueResultWithMultipleResults(RuntimeException e) { + assertThat( e, instanceOf( org.hibernate.NonUniqueResultException.class ) ); + } + @Override public void onGetSingleResultWithMultipleResults(RuntimeException e) { assertThat( e, instanceOf( jakarta.persistence.NonUniqueResultException.class ) ); @@ -266,6 +281,8 @@ interface ExceptionExpectations { void onInvalidQueryExecuted(RuntimeException e); + void onUniqueResultWithMultipleResults(RuntimeException e); + void onGetSingleResultWithMultipleResults(RuntimeException e); void onGetSingleResultWithNoResults(RuntimeException e); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/exceptionhandling/QueryExceptionHandlingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/exceptionhandling/QueryExceptionHandlingTest.java index b016be0cf6..a8ef96fd9f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/exceptionhandling/QueryExceptionHandlingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/exceptionhandling/QueryExceptionHandlingTest.java @@ -63,6 +63,19 @@ public class QueryExceptionHandlingTest extends BaseExceptionHandlingTest { } } + @Test + public void testUniqueResultWithMultipleResults() { + try { + TransactionUtil2.inSession( sessionFactory(), s -> { + s.createQuery( "from A where id in (1, 2)" ).uniqueResult(); + } ); + fail( "should have thrown an exception" ); + } + catch (RuntimeException expected) { + exceptionExpectations.onUniqueResultWithMultipleResults( expected ); + } + } + @Test @TestForIssue(jiraKey = "HHH-13300") public void testGetSingleResultWithMultipleResults() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/QueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/QueryTest.java index 2b1a46ea70..25aeecbdf7 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/QueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/QueryTest.java @@ -16,6 +16,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityManager; import jakarta.persistence.NoResultException; +import jakarta.persistence.NonUniqueResultException; import jakarta.persistence.Parameter; import jakarta.persistence.PersistenceException; import jakarta.persistence.Query; @@ -1512,4 +1513,23 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase { entityManager.close(); } } + + @Test + public void testGetSingleResultWithManyResultsException() { + final EntityManager entityManager = getOrCreateEntityManager(); + try { + entityManager.getTransaction().begin(); + entityManager.persist( new Item( "1", "1" ) ); + entityManager.persist( new Item( "2", "2" ) ); + entityManager.createQuery( "FROM Item" ).getSingleResult(); + fail( "Expected NoResultException" ); + } + catch ( Exception e ) { + assertTyping( NonUniqueResultException.class, e ); + } + finally { + entityManager.getTransaction().rollback(); + entityManager.close(); + } + } }