IT

JPA getSingleResult () 또는 널

lottoking 2020. 7. 11. 09:17
반응형

JPA getSingleResult () 또는 널


존재하지 않는 경우 insertOrUpdate삽입 Entity하거나 존재하는 경우 업데이트 하는 메소드 가 있습니다. 나는 사용하는 경우, 나는에 가지고 findByIdAndForeignKey가 반환하지 않을 경우 업데이트 null를 사용합니다. 어떻게 확인 확인합니까? 그래서 나는 노력했다 getSingleResult. 그러나 예외가 발생하면

public Profile findByUserNameAndPropertyName(String userName, String propertyName) {
    String namedQuery = Profile.class.getSimpleName() + ".findByUserNameAndPropertyName";
    Query query = entityManager.createNamedQuery(namedQuery);
    query.setParameter("name", userName);
    query.setParameter("propName", propertyName);
    Object result = query.getSingleResult();
    if (result == null) return null;
    return (Profile) result;
}

하지만 getSingleResult던졌습니다 Exception.

감사합니다


예외를 던지면 그렇다고합니다. 개인적으로 나는 이런 종류의 API를 견딜 수 없습니다. 모든 경우에 모든 것이 허위 예외 처리를 강요합니다. try-catch 블록으로 코드를 사용하면됩니다.getSingleResult()

또는 목록을 쿼리하여 비어 있는지 확인할 수 있습니다. 예외는 아닙니다. (외래 키 또는 제약 조건 중 하나 또는 둘 다 또는 조합으로 불가능한 경우에도) 기술적으로 기본 키 조회를하지 않기 때문에 여러 결과가있을 수 있습니다. 이것은 아마도 더 해결책 일 것입니다.


다음 도우미 메서드에서 논리를 캡슐화했습니다.

public class JpaResultHelper {
    public static Object getSingleResultOrNull(Query query){
        List results = query.getResultList();
        if (results.isEmpty()) return null;
        else if (results.size() == 1) return results.get(0);
        throw new NonUniqueResultException();
    }
}

이 작업을 수행하기위한 좋은 옵션이 있습니다.

public static <T> T getSingleResult(TypedQuery<T> query) {
    query.setMaxResults(1);
    List<T> list = query.getResultList();
    if (list == null || list.isEmpty()) {
        return null;
    }

    return list.get(0);
}

Java 8에서 시도하십시오.

Optional first = query.getResultList().stream().findFirst();

Spring 은이를위한 유틸리티 메소드가지고 있습니다 .

TypedQuery<Profile> query = em.createNamedQuery(namedQuery, Profile.class);
...
return org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());

(Java 8에서) 완료되었습니다.

query.getResultList().stream().findFirst().orElse(null);

try / catch 사용하여 하여이 문제를 처리하려는 경우 if / else처럼 작동하는 데 사용할 수 있습니다. 기존의 레코드를 사용하여 새 레코드를 추가했습니다.

try {  //if part

    record = query.getSingleResult();   
    //use the record from the fetched result.
}
catch(NoResultException e){ //else part
    //create a new record.
    record = new Record();
    //.........
    entityManager.persist(record); 
}

다음은 Rodrigo IronMan의 구현을 기반으로 한 유형 / 일반 버전입니다.

 public static <T> T getSingleResultOrNull(TypedQuery<T> query) {
    query.setMaxResults(1);
    List<T> list = query.getResultList();
    if (list.isEmpty()) {
        return null;
    }
    return list.get(0);
}


내가 추천 할 대안이 있습니다.

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

이것은 Null Pointer Exception에 대한 보호를 제공하며 1 개의 결과 만 반환됩니다.


그러니 하지마!

두 가지 옵션이 있습니다.

  1. 선택을 실행하여 개수가 0이 아닌 경우에만 데이터를 가져옵니다. 또는

  2. 다른 종류의 쿼리 (결과 집합을 가져옴)를 사용하고 결과가 0 개 이상인지 확인합니다. 1이 꺼내면 완료됩니다.

나는 Cletus와 동의하여 두 제안을 제안 할 것입니다. (잠재적으로) 2 개의 쿼리보다 더 나은 성능을 제공합니다. 또한 작업량이 적습니다.


uniqueResultOptionalorg.hibernate.query.Query 의 문서화되지 않은 메소드 가 트릭을 수행해야합니다. 대신 잡을 필요의 NoResultException당신은 단지 호출 할 수 있습니다 query.uniqueResultOptional().orElse(null).


기존의 유용한 유용한 비트 (결과 수 제한, 결과가 고유한지 확인)를 결합하고 안정화 된 방법 이름 (Hibernate)을 사용할 수 있습니다.

/**
 * Return a single instance that matches the query, or null if the query returns no results.
 *
 * @param query query (required)
 * @param <T> result record type
 * @return record or null
 */
public static <T> T uniqueResult(@NotNull TypedQuery<T> query) {
    List<T> results = query.setMaxResults(2).getResultList();
    if (results.size() > 1) throw new NonUniqueResultException();
    return results.isEmpty() ? null : results.get(0);
}

나는 0 List<?> myList = query.getResultList();myList.size()같은지 사용 하고 확인 하여 해결했습니다 .


다음은 Google Guava 및 TypedQuery를 사용하여 다른 사람들이 제안한 것과 동일한 논리입니다 (resultList 가져 오기, 유일한 요소 또는 null 반환).

public static <T> getSingleResultOrNull(final TypedQuery<T> query) {
    return Iterables.getOnlyElement(query.getResultList(), null); 
}

Guava는 결과 집합에 둘 이상의 결과가있는 경우 제공되지 않은 IllegalArgumentException을 반환합니다. (이 예외는 getOnlyElement ()의 클라이언트 보유한 의미가 있는데, 이는 결과 목록을 인수로 취하지 만 getSingleResultOrNull ()의 클라이언트에게는 이해하기 어렵 기 때문입니다.)


이번에는 Scala에서 또 다른 확장이 있습니다.

customerQuery.getSingleOrNone match {
  case Some(c) => // ...
  case None    => // ...
}

이 포주와 함께 :

import javax.persistence.{NonUniqueResultException, TypedQuery}
import scala.collection.JavaConversions._

object Implicits {

  class RichTypedQuery[T](q: TypedQuery[T]) {

    def getSingleOrNone : Option[T] = {

      val results = q.setMaxResults(2).getResultList

      if (results.isEmpty)
        None
      else if (results.size == 1)
        Some(results.head)
      else
        throw new NonUniqueResultException()
    }
  }

  implicit def query2RichQuery[T](q: TypedQuery[T]) = new RichTypedQuery[T](q)
}

따라서이 페이지의 모든 "예외없이 다시 쓰기 시도"솔루션에는 사소한 문제가 있습니다. NonUnique 예외가 발생하지 않는 경우 잘못된 경우에도 발생합니다 (아래 참조).

적절한 해결책은 (아마도)

public static <L> L getSingleResultOrNull(TypedQuery<L> query) {
    List<L> results = query.getResultList();
    L foundEntity = null;
    if(!results.isEmpty()) {
        foundEntity = results.get(0);
    }
    if(results.size() > 1) {
        for(L result : results) {
            if(result != foundEntity) {
                throw new NonUniqueResultException();
            }
        }
    }
    return foundEntity;
}

목록에 0 개의 것이 있다면 null로 반환되고, 목록에 다른 요소가 있으면 고유하지 않은 값을 반환하지만 선택 항목 중 하나가 제대로 설계되지 않은 경우 고유하지 않은 값을 반환하지 않습니다. .

의견을 바랍니다.


이 코드를 사용 :

return query.getResultList().stream().findFirst().orElse(null);

findFirst()호출 어쩌면 NullPointerException이 발생했습니다.

가장 좋은 방법은 다음과 가능합니다.

return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);


결과 목록을 얻은 다음 비어 있는지 확인하여 달성했습니다.

public boolean exist(String value) {
        List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList();
        return !options.isEmpty();
    }

너무 짜증나서 getSingleResult()예외가 발생합니다.

던졌다 :

  1. NoResultException- 결과가없는 경우
  2. NonUniqueResultException- 문서에서 더 많은 정보를 얻을 수있는 둘 이상의 결과 및 기타 예외 인 경우

JPA 2.2 에서 .getResultList()목록이 비어 있는지 확인하거나 스트림을 만드는 대신 스트림을 반환하고 첫 번째 요소를 사용할 수 있습니다.

.getResultStream()
.findFirst()
.orElse(null);

저에게 효과가 있습니다.

Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;

참고 URL : https://stackoverflow.com/questions/2002993/jpa-getsingleresult-or-null

반응형