JPA getSingleResult()或 null

我有一个 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

谢谢

258275 次浏览

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

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

所以别这么做!

你有两个选择:

  1. 运行一个选择来获取结果集的 COUNT,并且只有当该计数为非零时才引入数据; 或者

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

我同意克莱图斯的第二个建议。它比(潜在的)2个查询提供更好的性能。工作量也少了。

我将逻辑封装在下面的 helper 方法中。

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

下面的逻辑与其他建议的逻辑相同(获取 result 列表,返回它唯一的元素或 null) ,使用 Google Guava 和 TypedQuery。

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

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

这里有一个不错的选择:

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

我还有一个建议:

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

这将防止 Null 指针异常,保证只返回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)
}

如果您希望使用 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);
}

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

Spring 为此提供了 一种实用的方法:

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

所以这个页面中的所有“尝试无例外地重写”解决方案都有一个小问题。它既不抛出 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,如果列表中有不同的元素,则返回 non-only,但是如果您的选择之一设计不当,并且多次返回同一个对象,则不返回 non-only。

欢迎评论。

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

在 Java8中尝试这样做:

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

在 org.hibernate.query 中未记录的方法 uniqueResultOptional。查询应该就可以了。你可以直接调用 query.uniqueResultOptional().orElse(null),而不必捕获 NoResultException

我已经完成了(在 Java8中) :

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

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

这对我很有用:

Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : 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()并检查 list 是否为空或创建流,而是返回 stream 并获取第一个元素。

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

如果你可以使用新的 JPA 特性,我更喜欢@Serafins 的回答,但是这是一个相当直接的方法,我很惊讶之前没有在这里提到过:

    try {
return (Profile) query.getSingleResult();
} catch (NoResultException ignore) {
return null;
}
            `public Example validate(String param1) {
// TODO Auto-generated method stub


Example example = new Example();
                

Query query =null;
Object[] myResult =null;
                

try {


query = sessionFactory.getCurrentSession()
.createQuery("select column from table where
column=:p_param1");
query.setParameter("p_param1",param1);
}
                

myResult = (Object[])query.getSingleResult();//As your problem occurs here where the query has no records it is throwing an exception
                    

String obj1 = (String) myResult[0];
String obj2 = (String) myResult[1];
                        

                        

Setobj1(ISSUtil.ConvertNullToSpace (objec1)) Setobj2(ISSUtil.ConvertNullToSpace (objec2)) ;

                return example;
                

}catch(Exception e) {
e.printStackTrace();
                      

example.setobj1(ISSUtil.convertNullToSpace(""));//setting
objects to "" in exception block
example.setobj1(ISSUtil.convertNullToSpace(""));
}
return example;
}`

答: 显然,当没有记录时,getsinglerresult 会抛出一个异常,我通过在异常块中将对象设置为“”来处理这个异常,即使它输入的是 JSON 对象将设置为“”/null 的异常 希望这不是一个完美的答案,但它可能有所帮助 如果有人需要更精确地修改我的代码并纠正我,欢迎随时来找我。