JPA getSingleResult()或null

时间:2010-01-04 23:15:24

标签: java jpa

我有一个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会引发{{1}}。

由于

21 个答案:

答案 0 :(得分:235)

抛出异常是getSingleResult()表示无法找到的异常。我个人无法忍受这种API。它强制虚假的异常处理没有真正的好处。您只需将代码包装在try-catch块中即可。

或者,您可以查询列表并查看其是否为空。这不会引发异常。实际上,因为你没有在技术上进行主键查找,所以可能有多个结果(即使一个,两个或外键或约束的组合使得这在实践中不可能),所以这可能是更合适的解决方案。

答案 1 :(得分:31)

我在下面的帮助方法中封装了逻辑。

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

答案 2 :(得分:22)

这是一个很好的选择:

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

答案 3 :(得分:16)

在Java 8中试试这个:

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

答案 4 :(得分:14)

Spring为此a utility method

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

答案 5 :(得分:7)

如果您希望使用try / catch机制来处理这个问题,那么它可以像if / else一样使用。当我找不到现有记录时,我使用try / catch添加新记录。

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

答案 6 :(得分:6)

我已经完成了(在Java 8中):

@Override
public void onResponse(VolleyResponseBean response) {
    if (response.isValidateWebServiceType(response)) {
        switch (response.getWebServiceType()) {
            case GET_LATEST_POST:
                    ArrayList<LatestPost> resposneObject = (ArrayList<LatestPost>) (ArrayList<?>)response.getWordPressDataList();
                    LogUtils.LOGD(TAG, "Response sucessful" + resposneObject );
                latestPostTitle = new String[resposneObject.size()];
                latestPostImage = new String[resposneObject.size()];
                latestPostId = new Double[resposneObject.size()];
                latestPostDate = new String[resposneObject.size()];

                for(int i=0;i<resposneObject.size();++i){
                    mapLatestPost = (Map<String,Object>)resposneObject.get(i);
                    mapLatestTitle = (Map<String, Object>) mapLatestPost.get("title");
                    latestPostTitle[i] = (String) mapLatestTitle.get("rendered");
                    mapLatestContent = (Map<String, Object>) mapLatestPost.get("content");
                    latestPostImage[i] = (String) mapLatestContent.get("medium");
                    latestPostId[i] = (Double) mapLatestPost.get("id");
                    latestPostDate[i] = (String) mapLatestPost.get("date");
                }

答案 7 :(得分:6)

这是一个基于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);
}

答案 8 :(得分:4)

所以不要那样做!

您有两种选择:

  1. 运行选择以获取结果集的COUNT,如果此计数不为零,则仅提取数据;或

  2. 使用其他类型的查询(获取结果集)并检查它是否有0或更多结果。它应该有1,所以从你的结果集合中拉出它就完成了。

  3. 我同意Cletus的第二个建议。它提供比(可能)2个查询更好的性能。也少工作。

答案 9 :(得分:4)

我建议有另一种选择:

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

这可以防止Null Pointer Exception,保证只返回1个结果。

答案 10 :(得分:3)

org.hibernate.query.Query中的未记录方法uniqueResultOptional应该可以解决问题。您无需接听NoResultException,而只需拨打query.uniqueResultOptional().orElse(null)

答案 11 :(得分:2)

结合现有答案的有用位(限制结果数量,检查结果是唯一的)并使用已建立的方法名称(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);
}

答案 12 :(得分:2)

我使用List<?> myList = query.getResultList();并检查myList.size()是否等于零来解决这个问题。

答案 13 :(得分:1)

这是另一个扩展,这次是在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)
}

答案 14 :(得分:1)

这是与其他人建议的相同的逻辑(获取resultList,返回其唯一元素或null),使用Google Guava和TypedQuery。

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

请注意,如果结果集有多个结果,Guava将返回非直观的IllegalArgumentException。 (该异常对getOnlyElement()的客户端有意义,因为它将结果列表作为其参数,但对于getSingleResultOrNull()的客户端则不太容易理解。)

答案 15 :(得分:0)

如果您可以使用新的 JPA 功能,我更喜欢 @Serafins 的回答,但这是一种相当直接的方法,我很惊讶之前没有提到过:

    try {
        return (Profile) query.getSingleResult();
    } catch (NoResultException ignore) {
        return null;
    }

答案 16 :(得分:0)

From JPA 2.2,而不是.getResultList()并检查列表是否为空或创建流,您可以返回流并获取第一个元素。

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

答案 17 :(得分:0)

我通过获取结果列表然后检查其是否为空来实现这一目标

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

太烦人了,getSingleResult()抛出异常

投掷:

  1. NoResultException-如果没有结果
  2. NonUniqueResultException-如果多个结果 还有一些其他例外,您可以从他们的文档中获取更多信息

答案 18 :(得分:0)

查看此代码:

nslookup <ingress_url>

调用return query.getResultList().stream().findFirst().orElse(null);时可能会引发NullPointerException。

最好的方法是:

findFirst()

答案 19 :(得分:0)

因此,本页中的所有“尝试重写无异常”解决方案都存在一个小问题。它不会抛出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;如果列表中有不同的元素,则返回非唯一,但如果未正确设计其中一个select,则返回非唯一,并且返回同一个对象超过一次。

随意发表评论。

答案 20 :(得分:-1)

那对我有用:

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