2012-04-24 18 views
7

Normalmente trabajo con NoResultException para devolver un objeto "vacío", p. Ej. una lista de errores vacía o un nuevo BigInteger ("0"), si no obtengo ningún resultado de un TypedQuery. Ahora resultó que esto a veces no funciona. De repente getSingleResult() devuelve null en lugar de causar una NoResultException, y no entiendo por qué. Mira este ejemplo:JPA: TypedQuery a veces devuelve null en lugar de 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 de la Entidad ...

@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"; 
. 
. 
. 

Si uso accountId que hace que no hay resultados, me sale nulo en lugar de NoResultException. ¿Alguna idea de por qué esto es así? Incluso Javadoc de TypedQuery dice que tiene que volver 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(); 

Respuesta

19

Parece un comportamiento correcto para mí.

NoResultException se arroja cuando no se devuelven las filas, pero sum devuelve exactamente una fila con el valor null en su caso. De JPA 2.0 Especificación:

Si, AVG, MAX, o se utiliza SUM MIN, y no hay valores a los cuales la función de agregación puede ser aplicado, el resultado de la función de agregado es NULL.

Si desea obtener 0 en lugar de null, utilice coalesce:

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

complicado, pero que lo explica todo, gracias. – Bevor

+0

Entiendo que AVG, MAX y MIN de un conjunto vacío no están definidos, pero SUMA de un conjunto vacío es 0. Me pregunto por qué fallan. – VinyJones

+0

SUM, AVG, MAX o MIN pueden ser 0 para un conjunto no vacío también. La devolución nula confirma el conjunto vacío. – Ritesh

Cuestiones relacionadas