2012-04-24 33 views
7

Thông thường, tôi làm việc với NoResultException để trả về một đối tượng "trống", ví dụ: một danh sách lỗi rỗng hoặc BigInteger mới ("0"), nếu tôi không nhận được kết quả từ một TypedQuery. Bây giờ nó bật ra rằng điều này đôi khi không hoạt động. Đột nhiên getSingleResult() trả về null thay vì gây ra một NoResultException, và tôi không hiểu tại sao. Nhìn ví dụ này:JPA: TypedQuery đôi khi trả về null thay vì 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"); 
    } 
} 

Phần quan trọng của 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"; 
. 
. 
. 

Nếu tôi sử dụng một AccountID gây không có kết quả, tôi nhận được null thay vì NoResultException. Bất kỳ ý tưởng tại sao điều này là như vậy? Ngay cả Javadoc của TypedQuery cũng nói rằng nó phải trả lại 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(); 

Trả lời

19

Dường như là một hành vi đúng đắn đối với tôi.

NoResultException được ném khi không có hàng nào được trả lại, nhưng sum trả lại chính xác một hàng với giá trị null trong trường hợp của bạn. Từ Đặc điểm kỹ thuật JPA 2.0:

Nếu SUM, AVG, MAX hoặc MIN được sử dụng và không có giá trị mà chức năng tổng hợp có thể là được áp dụng, kết quả của hàm tổng hợp là NULL.

Nếu bạn muốn nhận được 0 thay vì null, sử dụng coalesce:

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

Tricky, nhưng điều đó giải thích nó, cảm ơn. – Bevor

+0

Tôi hiểu rằng AVG, MAX và MIN của tập trống không được xác định, nhưng SUM của tập trống là 0. Tôi tự hỏi tại sao chúng không thành công. – VinyJones

+0

SUM, AVG, MAX hoặc MIN có thể bằng 0 đối với bộ không trống. Trả về null xác nhận tập rỗng. – Ritesh

Các vấn đề liên quan