2011-12-14 14 views
10

Potrzebuję pobrać pojedynczy wiersz ze stołu, a ja byłem zainteresowany, jakie podejście jest lepsze. Po jednej stronie getSingleResult jest przeznaczony do pobierania pojedynczego wyniku, ale podnosi wyjątek. Czy ta metoda ma korzyści w wydajności związanej getResultList zco jest lepsze: getSingleResult lub getResultList JPA

query.setFirstResult(0); 
query.setMaxResults(1); 
+0

"ale to podnosi ekscepcję." Co to za wyjątek? (W rzeczywistości oba mogą podnieść wyjątek). Nie wiem o wydajności (w zależności od tego, która z nich jest bardziej wydajna, powinna być pomijalna), ale myślę, że 'getSingleResult' sprawia, że ​​twój kod jest bardziej czytelny. –

+0

tak, zgadzam się, że getSingleResult jest o wiele bardziej czytelny. Chcę tylko dowiedzieć się, co jest bardziej efektywne. – Pilgrim

Odpowiedz

9

getSingleResult rzuca NonUniqueResultException, jeśli istnieje wiele wierszy. Jest przeznaczony do pobierania pojedynczego wyniku, gdy istnieje naprawdę pojedynczy wynik.

Sposób, w jaki zrobiłeś, jest w porządku, a JPA ma na celu odpowiednie obsłużenie tego. W tym samym czasie nie można go porównać z getSingleResult w żaden sposób, ponieważ nie będzie działać.

Jednak w zależności od kodu, nad którym pracujesz, zawsze lepiej jest zawęzić zapytanie, aby zwrócić pojedynczy wynik, jeśli to wszystko, czego chcesz - możesz po prostu zadzwonić pod numer getSingleResult.

+1

, ale muszę obsługiwać wyjątek notFound. Ta część kodu musi uzyskać jednostkę konta użytkownika za pomocą kodu potwierdzającego e-mail. Rozumiem, że o wiele jaśniejsze jest użycie getSingleResult do tego, ale jestem świadomy obsługi wyjątków narzutowych – Pilgrim

+0

W połączeniu z 'fetch()' użycie 'setMaxResults (1)' może prowadzić do częściowo zainicjowanych obiektów. Zobacz poniżej przykład. – Leukipp

3

Istnieje alternatywa które polecam:

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

This zabezpieczeń przed Null Pointer wyjątku gwarancje tylko 1 wynik jest zwracany.

+1

dlaczego CollectionUtils zamiast tylko elementList.isEmpty()? – Tomasz

+0

@ TomTom Korzystanie z [http://commons.apache.org/collections/apidocs/org/apache/commons/collections/CollectionUtils.html#isEmpty(java.util.Collection)], isEmpty() zwraca true, jeśli lista ma wartość pustą lub zerową.CollectionUtils zapewnia łatwą czytelność kodu zamiast pisać: '(elementList! = Null) &&! ElementList.isEmpty().' –

+1

Z jakiego operatora korzystasz? EclipseLink's [EJBQueryImpl.getResultList()] (http://grepcode.com/file/maven.glassfish.org/content/repositories/eclipselink/org.eclipse.persistence/org.eclipse.persistence.jpa/2.1.1/org /eclipse/persistence/internal/jpa/EJBQueryImpl.java#EJBQueryImpl.getResultList%28%29) zwraca pustą listę zaczynającą się od never null – Tomasz

15

Według Effective Java przez Joshua Bloch:

Korzystanie sprawdzone wyjątki od warunków wich rozmówcy mogą zasadnie oczekiwać, aby odzyskać. Użyj wyjątków czasu wykonywania, aby wskazać błędy programowania .

kredytowych do źródła: Why you should never use getSingleResult() in JPA

@Entity 
@NamedQuery(name = "Country.findByName", 
      query = "SELECT c FROM Country c WHERE c.name = :name" 
public class Country { 
    @PersistenceContext 
    transient EntityManager entityManager; 

    public static Country findByName(String name) { 
     List<Country> results = entityManager 
      .createNamedQuery("Country.findByName", Country.class) 
      .setParameter("name", name).getResultList(); 
     return results.isEmpty() ? null : results.get(0); 
    } 
} 
+1

Dziękuję bardzo, bardzo rozsądne wyjaśnienie – Pilgrim

+0

Istnieje bardzo niewiele absolutów w Javie i ten, który ten artykuł głosi nie jest prawidłowy we wszystkich przypadkach użycia. Jeśli na przykład zapytanie powinno zawsze zwracać jeden wiersz, aby spełnić pewne wymagania biznesowe, po co wydawać cykle, aby przygotować listę wyników, aby sprawdzić liczbę, aby sprawdzić, czy warunek biz został naruszony, gdy można wywołać getSingleResult i uchwycić wyjątki NoResultException/NoUniqueResultException i podjąć odpowiednie działania? Jest to mniej kodu i wykorzystuje wyjątki, aby wymusić wyjątkowe warunki logiki biz. – NBW

+1

@NBW krótka odpowiedź, ponieważ obsługa wyjątków jest bardziej zasobochłonna i ogólnie uważana za anty-wzór w tym przypadku http://programmers.stackexchange.com/questions/107723/arguments-for-or-against-using-try-catch- as-logiczne-operatory http://programmers.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why http://c2.com/ cgi/wiki? DontUseExceptionsForFlowControl – Tomasz

1

getSingleResult rzuca NonUniqueResultException, jeśli istnieje wiele wierszy lub nie żadnych wierszy. Jest przeznaczony do pobierania pojedynczego wyniku, gdy istnieje naprawdę pojedynczy wynik.

1

W połączeniu z fetch() użycie setMaxResults(1) może prowadzić do częściowo zainicjalizowanych obiektów. Na przykład,

CriteriaQuery<Individual> query = cb.createQuery(Individual.class); 
Root<Individual> root = query.from(Individual.class); 
root.fetch(Individual_.contacts); 

query.where(cb.equal(root.get(Individual_.id), id)); 

Individual i = em.createQuery(query) 
    .setMaxResults(1) // assertion fails if individual has 2 contacts 
    .getResultList() 
    .get(0); 
assertEquals(2, i.getContacts().size()); 

Tak, używam getResultList() bez limitu - trochę niezadowalające.

Powiązane problemy