2012-04-24 13 views
7

Di solito lavoro con NoResultException per restituire un oggetto "vuoto", ad es. un elenco di errori vuoto o un nuovo BigInteger ("0"), se non ottengo risultati da un TypedQuery. Ora si è scoperto che a volte questo non funziona. Improvvisamente getSingleResult() restituisce null invece di causare una NoResultException, e non capisco perché. Guardate questo esempio:JPA: TypedQuery restituisce talvolta null invece di NoResultException

public BigInteger pointsSumByAccountId(long accountId) 
{ 
    try 
    { 
     TypedQuery<BigInteger> pointsQuery = entityManager.createNamedQuery(Points.SumByAccountId, BigInteger.class); 
     pointsQuery.setParameter(Points.AccountIdParameter, accountId); 

     return pointsQuery.getSingleResult(); 
    } 
    catch (NoResultException e) 
    { 
     return new BigInteger("0"); 
    } 
} 

La parte importante della Entity ...

@NamedQueries({@NamedQuery(name = "Points.sumByAccountId", query = "select sum(p.value) from Points p where p.validFrom <= current_timestamp() and p.validThru >= current_timestamp() and p.account.id = :accountId")}) 
public class Points 
{ 
    private static final long serialVersionUID = -15545239875670390L; 

    public static final String SumByAccountId = Points.class.getSimpleName() + ".sumByAccountId"; 
    public static final String AccountIdParameter = "accountId"; 
. 
. 
. 

Se uso un accountid che provoca alcun risultato, ottengo nulla, invece di NoResultException. Qualche idea per cui è così? Anche Javadoc di TypedQuery dice che deve tornare NoResultException:

/** 
* Execute a SELECT query that returns a single result. 
* 
* @return the result 
* 
* @throws NoResultException if there is no result 
* @throws NonUniqueResultException if more than one result 
* @throws IllegalStateException if called for a Java 
* Persistence query language UPDATE or DELETE statement 
* @throws QueryTimeoutException if the query execution exceeds 
* the query timeout value set and only the statement is 
* rolled back 
* @throws TransactionRequiredException if a lock mode has 
* been set and there is no transaction 
* @throws PessimisticLockException if pessimistic locking 
* fails and the transaction is rolled back 
* @throws LockTimeoutException if pessimistic locking 
* fails and only the statement is rolled back 
* @throws PersistenceException if the query execution exceeds 
* the query timeout value set and the transaction 
* is rolled back 
*/ 
X getSingleResult(); 

risposta

19

Sembra un comportamento corretto per me.

NoResultException viene generato quando non viene restituita alcuna riga, ma sum restituisce esattamente una riga nel valore null nel caso. Da JPA 2.0 Specifica:

Se SUM, AVG, MAX o MIN viene utilizzato, e non ci sono valori che la funzione di aggregazione può essere applicata , il risultato della funzione di aggregazione è NULL.

Se si desidera ottenere 0 invece di null, utilizzare coalesce:

select coalesce(sum(p.value), 0) ... 
+1

Tricky, ma che spiega tutto, grazie. – Bevor

+0

Capisco che AVG, MAX e MIN di un set vuoto non sono definiti, ma SUM di un set vuoto è 0. Mi chiedo perché non ci riescono. – VinyJones

+0

SUM, AVG, MAX o MIN possono essere 0 anche per un set non vuoto. Restituire null conferma il set vuoto. – Ritesh

Problemi correlati