158

I have an insertOrUpdate method which inserts an Entity when it doesn't exist or update it if it does. To enable this, I have to findByIdAndForeignKey, if it returned null insert if not then update. The problem is how do I check if it exists? So I tried getSingleResult. But it throws an exception if the

public Profile findByUserNameAndPropertyName(String userName, String propertyName) {
    String namedQuery = Profile.class.getSimpleName() + ".findByUserNameAndPropertyName";
    Query query = entityManager.createNamedQuery(namedQuery);
    query.setParameter("name", userName);
    query.setParameter("propName", propertyName);
    Object result = query.getSingleResult();
    if (result == null) return null;
    return (Profile) result;
}

but getSingleResult throws an Exception.

Thanks

dur
  • 15,689
  • 25
  • 79
  • 125
Eugene Ramirez
  • 3,053
  • 2
  • 23
  • 17
  • 1
    `getSingleResult()` forces you to use exception handling in absence of a value, even though the absence of a value is a common and natural situation. Best practices are that exceptions should only be used for exceptional situations, which the absence of a value is not. A lot of people don't like `getSingleResult()` for this reason. Even the authors of Hibernate, from which JPA was born, criticize `getSingleResult()`. If you also don't like it, please upvote: https://github.com/eclipse-ee4j/jpa-api/issues/298 – Devabc Nov 29 '20 at 23:47

22 Answers22

294

Throwing an exception is how getSingleResult() indicates it can't be found. Personally I can't stand this kind of API. It forces spurious exception handling for no real benefit. You just have to wrap the code in a try-catch block.

Alternatively you can query for a list and see if its empty. That doesn't throw an exception. Actually since you're not doing a primary key lookup technically there could be multiple results (even if one, both or the combination of your foreign keys or constraints makes this impossible in practice) so this is probably the more appropriate solution.

Sk8erPeter
  • 6,899
  • 9
  • 48
  • 67
cletus
  • 616,129
  • 168
  • 910
  • 942
  • Depends - should you be asking for something that doesn't exist? Also what happens if the value you are looking up is null? (I am not familiar enough with the API to know what it would do - but if null is a valid return value then the only thing left is to throw an exception if the value cannot be found). – TofuBeer Jan 05 '10 at 01:21
  • 1
    Null is not a valid return value. These functions are used to find if something is there or not. That's not (at least to me) good criteria for exception handling. It's exception handling flow control basically. – cletus Jan 05 '10 at 01:41
  • 129
    I don't agree, `getSingleResult()` is used in situations like: "*I am totally sure that this record exists. Shoot me if it doesn't*". I don't want to test for `null` every time I use this method because I am *sure* that it will not return it. Otherwise it causes a lot of boilerplate and defensive programming. And if the record really does not exist (as opposite to what we've assumed), it is much better to have `NoResultException` compared to `NullPointerException` few lines later. Of course having two versions of `getSingleResult()` would be awesome, but if I have to pick up one... – Tomasz Nurkiewicz Mar 17 '11 at 07:31
  • 1
    Its a RuntimeException so is indicating a programming error. ie. you should only be calling getSingleResult() if one and only one row will be returned. – objects Mar 06 '12 at 06:34
  • 12
    @cletus Null is indeed a valid return value for a database. – Bill Rosmus Jun 12 '12 at 20:19
  • 19
    @TomaszNurkiewicz that's a good point. However, seems like there should be some type of "getSingleResultOrNull". I guess you could create a wrapper for such. – cbmeeks Jun 21 '13 at 21:54
  • 1
    @TomaszNurkiewicz I think the correct behaviour would be if the language had the concept of Optional to return Optional. of singleResult. Its usually bad API design to return null as that means the caller needs to check two places the null could bubble up through the callers. Great comment btw. – Wes Feb 03 '14 at 15:57
  • 1
    For me there is only one scenario where you should use `getSingleResult()`, when you use aggregate functions like `count`. In all other cases I also prefer `getResultList()`. – Mathias Begert Jan 12 '15 at 15:36
  • 6
    Here is some info in term of benefit of exception begin thrown from getSingleResult(): Queries can be used to retrieve almost anything including the value of a single column in a single row. If getSingleResult() would return null, you could not tell whether the query did not match any row or whether the query matched a row but the selected column contains null as its value. from: http://stackoverflow.com/a/12155901/1242321 – user1242321 Mar 16 '16 at 01:36
  • 7
    It should return Optional. That is a good way to indicate missing values. – Vivek Kothari Apr 26 '16 at 10:59
  • 1
    Or instead of a `getSingleResult` a `getFirstResult`, so you can use it if there might be more results, and you just want one? – Johanneke Jan 23 '18 at 14:01
  • this is why dotnet linq has .First or .FirstOrDefault .. It gives you the option of whether you very sure it is there (.First) or you're kinda sure, but don't want an exception (.FirstOrDefault). not sure why java doesn't have these 2 options built in. (unless I'm missing something). Upvote for this explanation. – granadaCoder Mar 07 '19 at 00:14
  • @TomaszNurkiewicz "Otherwise it causes a lot of boilerplate and defensive programming" I think it would have required much less boilerplate if getSingleResult() were intended for general use instead, or even if I could just let its exception float out for a 404. The EJB intention for every generic exception to be a system exception is really unfortunate. – Alkanshel Apr 14 '20 at 00:16
  • 1
    @TomaszNurkiewicz *Effective Java* (by Joshua Bloch, a famous Java Language engineer) says: "*Use exceptions only for exceptional conditions.*". The absence of a value is not an exceptional condition. Bloch also says: "*A well-designed API must not force its clients to use exceptions for ordinary control flow.*". `getSingleResult()` clearly violates both of these rules. Imagine if every `getElement()` like method would throw an exception in the absence of a value, that would be a hell for Java developers. – Devabc Nov 29 '20 at 22:14
52

Try this in Java 8:

Optional first = query.getResultList().stream().findFirst();
Pang
  • 9,564
  • 146
  • 81
  • 122
Impala67
  • 529
  • 4
  • 2
35

I encapsulated the logic in the following helper method.

public class JpaResultHelper {
    public static Object getSingleResultOrNull(Query query){
        List results = query.getResultList();
        if (results.isEmpty()) return null;
        else if (results.size() == 1) return results.get(0);
        throw new NonUniqueResultException();
    }
}
Eugene Katz
  • 5,208
  • 7
  • 40
  • 49
  • 2
    Note that you can be a bit more optimal by calling Query.setMaxResults(1). Sadly, since Query is stateful, you'll want to capture the value of Query.getMaxResults() and fix up the object in a try-finally block, and maybe just fail altogether if Query.getFirstResult() returns anything interesting. – Patrick Linskey Feb 24 '11 at 20:27
  • that's how we have it implemented on our project. Never had any issues with this implementation – walv Sep 13 '17 at 14:38
24

Here's a good option for doing this:

public static <T> T getSingleResult(TypedQuery<T> query) {
    query.setMaxResults(1);
    List<T> list = query.getResultList();
    if (list == null || list.isEmpty()) {
        return null;
    }

    return list.get(0);
}
nbrooks
  • 18,126
  • 5
  • 54
  • 66
Rodrigo IronMan
  • 249
  • 2
  • 2
  • 2
    Neat! I'd accept `TypedQuery` though, in which case the `getResultList()` is then already correctly typed as a `List`. – Rup Feb 13 '13 at 10:58
  • In combination with `fetch()` the entity might not be completely populated. See http://stackoverflow.com/a/39235828/661414 – Leukipp Aug 30 '16 at 19:44
  • 1
    This is a very nice approach. Note that `setMaxResults()` has a fluent interface so you can write `query.setMaxResults(1).getResultList().stream().findFirst().orElse(null)`. This should be the most efficient call scheme in Java 8+. – Dirk Hillbrecht Feb 11 '19 at 17:03
22

From JPA 2.2, instead of .getResultList() and checking if list is empty or creating a stream you can return stream and take first element.

.getResultStream()
.findFirst()
.orElse(null);
geisterfurz007
  • 5,292
  • 5
  • 33
  • 54
Serafins
  • 1,237
  • 1
  • 17
  • 36
  • 1
    or simply `.getResultStream().findFirst()` for an `Optional` – Markus Pscheidt Jul 21 '21 at 08:45
  • This defaults to `getResultList().stream()`. Unless you're confident that the implementation you're using overrides it, this can lead to performance issues, because fetching all rows vs fetching one row can be a difference between 20 ms and 20 minutes. – Kamil Bęben Feb 03 '23 at 12:44
21

I've done (in Java 8):

query.getResultList().stream().findFirst().orElse(null);
LovaBill
  • 5,107
  • 1
  • 24
  • 32
Zhurov Konstantin
  • 712
  • 1
  • 8
  • 14
20

Spring has a utility method for this:

TypedQuery<Profile> query = em.createNamedQuery(namedQuery, Profile.class);
...
return org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());
Didier L
  • 18,905
  • 10
  • 61
  • 103
heenenee
  • 19,914
  • 1
  • 60
  • 86
  • Keep in mind, that using [DataAccessUtils.singleResult](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/dao/support/DataAccessUtils.html) will throw an exception when there is more than one element. – Serafins Nov 03 '21 at 08:20
7

If you wish to use the try/catch mechanism to handle this problem.. then it can be used to act like if/else. I used the try/catch to add a new record when I didn't find an existing one.

try {  //if part

    record = query.getSingleResult();   
    //use the record from the fetched result.
}
catch(NoResultException e){ //else part
    //create a new record.
    record = new Record();
    //.........
    entityManager.persist(record); 
}
Sorter
  • 9,704
  • 6
  • 64
  • 74
6

Here's a typed/generics version, based on Rodrigo IronMan's implementation:

 public static <T> T getSingleResultOrNull(TypedQuery<T> query) {
    query.setMaxResults(1);
    List<T> list = query.getResultList();
    if (list.isEmpty()) {
        return null;
    }
    return list.get(0);
}
Emmanuel Touzery
  • 9,008
  • 3
  • 65
  • 81
5

There is an alternative which I would recommend:

Query query = em.createQuery("your query");
List<Element> elementList = query.getResultList();
return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);

This safeguards against Null Pointer Exception, guarantees only 1 result is returned.

aces.
  • 3,902
  • 10
  • 38
  • 48
4

So don't do that!

You have two options:

  1. Run a selection to obtain the COUNT of your result set, and only pull in the data if this count is non-zero; or

  2. Use the other kind of query (that gets a result set) and check if it has 0 or more results. It should have 1, so pull that out of your result collection and you're done.

I'd go with the second suggestion, in agreement with Cletus. It gives better performance than (potentially) 2 queries. Also less work.

Carl Smotricz
  • 66,391
  • 18
  • 125
  • 167
3

Combining the useful bits of the existing answers (limiting the number of results, checking that the result is unique) and using the estabilshed method name (Hibernate), we get:

/**
 * Return a single instance that matches the query, or null if the query returns no results.
 *
 * @param query query (required)
 * @param <T> result record type
 * @return record or null
 */
public static <T> T uniqueResult(@NotNull TypedQuery<T> query) {
    List<T> results = query.setMaxResults(2).getResultList();
    if (results.size() > 1) throw new NonUniqueResultException();
    return results.isEmpty() ? null : results.get(0);
}
Peter Walser
  • 15,208
  • 4
  • 51
  • 78
3

The undocumented method uniqueResultOptional in org.hibernate.query.Query should do the trick. Instead of having to catch a NoResultException you can just call query.uniqueResultOptional().orElse(null).

at_sof
  • 39
  • 4
2

I solved this by using List<?> myList = query.getResultList(); and checking if myList.size() equals to zero.

TylerH
  • 20,799
  • 66
  • 75
  • 101
2

Look this code :

return query.getResultList().stream().findFirst().orElse(null);

When findFirst() is called maybe can be throwed a NullPointerException.

the best aproach is:

return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);

1

Here's another extension, this time in Scala.

customerQuery.getSingleOrNone match {
  case Some(c) => // ...
  case None    => // ...
}

With this pimp:

import javax.persistence.{NonUniqueResultException, TypedQuery}
import scala.collection.JavaConversions._

object Implicits {

  class RichTypedQuery[T](q: TypedQuery[T]) {

    def getSingleOrNone : Option[T] = {

      val results = q.setMaxResults(2).getResultList

      if (results.isEmpty)
        None
      else if (results.size == 1)
        Some(results.head)
      else
        throw new NonUniqueResultException()
    }
  }

  implicit def query2RichQuery[T](q: TypedQuery[T]) = new RichTypedQuery[T](q)
}
Pete Montgomery
  • 4,060
  • 3
  • 30
  • 40
1

So all of the "try to rewrite without an exception" solution in this page has a minor problem. Either its not throwing NonUnique exception, nor throw it in some wrong cases too (see below).

I think the proper solution is (maybe) this:

public static <L> L getSingleResultOrNull(TypedQuery<L> query) {
    List<L> results = query.getResultList();
    L foundEntity = null;
    if(!results.isEmpty()) {
        foundEntity = results.get(0);
    }
    if(results.size() > 1) {
        for(L result : results) {
            if(result != foundEntity) {
                throw new NonUniqueResultException();
            }
        }
    }
    return foundEntity;
}

Its returning with null if there is 0 element in the list, returning nonunique if there are different elements in the list, but not returning nonunique when one of your select is not properly designed and returns the same object more then one times.

Feel free to comment.

tg44
  • 810
  • 1
  • 8
  • 21
  • Thank God someone pointed out an obvious truth: if OP is calling getSingleResult() he is expecting the result to be unique, not to just get which happens to be the first in a (possibly unordered) query! With Java8 it's even cleaner: `getResultList().stream().distinct().reduce((a, b) -> {throw new NonUniqueResultException();}).orElse(null);` – Ilario Sep 04 '20 at 08:25
1

Here's the same logic as others suggested (get the resultList, return its only element or null), using Google Guava and a TypedQuery.

public static <T> getSingleResultOrNull(final TypedQuery<T> query) {
    return Iterables.getOnlyElement(query.getResultList(), null); 
}

Note that Guava will return the unintuitive IllegalArgumentException if the result set has more than one result. (The exception makes sense to clients of getOnlyElement(), as it takes the result list as its argument, but is less understandable to clients of getSingleResultOrNull().)

tpdi
  • 34,554
  • 11
  • 80
  • 120
0

I achieved this by getting a result list then checking if it is empty

public boolean exist(String value) {
        List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList();
        return !options.isEmpty();
    }

It is so annoying that getSingleResult() throws exceptions

Throws:

  1. NoResultException - if there is no result
  2. NonUniqueResultException - if more than one result and some other exception that you can get more info on from their documentation
Uchephilz
  • 508
  • 5
  • 7
0

I prefer @Serafins answer if you can use the new JPA features, but this is one fairly straight forward way to do it which I'm surprised hasn't been mentioned here before:

    try {
        return (Profile) query.getSingleResult();
    } catch (NoResultException ignore) {
        return null;
    }
splashout
  • 537
  • 5
  • 11
0
            `public Example validate(String param1) {
                // TODO Auto-generated method stub

                Example example = new Example();
                
                Query query =null;
                Object[] myResult =null;
                
                try {

                      query = sessionFactory.getCurrentSession()
                      .createQuery("select column from table where 
                      column=:p_param1");
                      query.setParameter("p_param1",param1);
                  }
                
                        myResult = (Object[])query.getSingleResult();//As your problem occurs here where the query has no records it is throwing an exception
                    
                        String obj1 = (String) myResult[0];
                        String obj2 = (String) myResult[1];
                        
                        

example.setobj1(ISSUtil.convertNullToSpace(obj1)) example.setobj2(ISSUtil.convertNullToSpace(obj2));

                return example;
                
                }catch(Exception e) {
                    e.printStackTrace();
                      
                 example.setobj1(ISSUtil.convertNullToSpace(""));//setting 
                 objects to "" in exception block
                 example.setobj1(ISSUtil.convertNullToSpace(""));
                }
                return example;
            }`

Answer : Obviously when there is no records getsingleresult will throw an exception i have handled it by setting the objects to "" in the exception block even though it enter the exception you JSON object will set to ""/empty Hope this is not a perfect answer but it might help If some needs to modify my code more precisely and correct me always welcome.

-3

Thats works to me:

Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;
peterzinho16
  • 919
  • 1
  • 15
  • 18