Что лучше: getSingleResult или getResultList JPA

Мне нужно получить одну строку из таблицы, и мне было интересно, какой подход лучше. С одной стороны getSingleResult предназначен для получения единственного результата, но он вызывает исключение. Имеет ли этот метод преимущества, связанные с getResultList с

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

Ответ 1

getSingleResult throws NonUniqueResultException, если имеется несколько строк. Он предназначен для получения единственного результата, когда есть действительно один результат.

То, как вы это сделали, прекрасно, и JPA спроектирован таким образом, чтобы справиться с этим. В то же время вы не можете сравнивать его с getSingleResult любым способом, так как он не будет работать.

Однако, в зависимости от кода, над которым вы работаете, всегда лучше уточнить запрос, чтобы возвращать единый результат, если это все, что вы хотите - тогда вы можете просто вызвать getSingleResult.

Ответ 2

Согласно эффективной Java от Джошуа Блоха:

Использовать проверенные исключения для условий, из которых может разумно ожидать восстановления. Использовать исключения во время выполнения, чтобы указать ошибки программирования.

Кредит источнику: Почему вы никогда не должны использовать getSingleResult() в 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);
  }
}

Ответ 3

Есть альтернатива, которую я бы рекомендовал:

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

Эта защита от Null Pointer Exception гарантирует, что возвращается только 1 результат.

Ответ 4

getSingleResult выбрасывает NonUniqueResultException, если существует несколько строк или нет любые строки. Он предназначен для получения единственного результата, когда есть действительно один результат.

Ответ 5

В сочетании с fetch() использование setMaxResults(1) может привести к частично инициализированным объектам. Например,

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());

Итак, я использую getResultList() без ограничений - немного неудовлетворительно.