JPA getSingleResult()或null

Eug*_*rez 128 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;
}
Run Code Online (Sandbox Code Playgroud)

getSingleResult扔了一个Exception.

谢谢

cle*_*tus 247

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

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

  • 我不同意,`getSingleResult()`用于以下情况:"*我完全相信这条记录存在.如果它没有*就拍我." 每次我使用这种方法时,我都不想测试`null`因为我确定*它不会返回它.否则会导致许多样板和防御性编程.如果记录确实不存在(与我们假设的相反),那么将'NoResultException`与`NullPointerException`相比较几行会好得多.当然有两个版本的`getSingleResult()`会很棒,但如果我要拿一个...... (106认同)
  • @TomaszNurkiewicz这是一个好点.但是,似乎应该有某种类型的"getSingleResultOrNull".我猜你可以为这样创建一个包装器. (10认同)
  • @cletus Null确实是数据库的有效返回值. (7认同)
  • 以下是从getSingleResult()抛出的异常开始的一些信息:查询可用于检索几乎任何内容,包括单行中单个列的值.如果getSingleResult()将返回null,则无法判断查询是否与任何行匹配,或者查询是否与行匹配,但所选列包含null作为其值.来自:http://stackoverflow.com/a/12155901/1242321 (2认同)
  • 它应该返回Optional <T>.这是指示缺失值的好方法. (2认同)

Eug*_*atz 32

我在以下帮助器方法中封装了逻辑.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您可以通过调用 Query.setMaxResults(1) 来优化一些。遗憾的是,由于 Query 是有状态的,您需要捕获 Query.getMaxResults() 的值并在 try-finally 块中修复该对象,如果 Query.getFirstResult() 返回任何有趣的内容,则可能完全失败。 (2认同)

小智 23

这是一个很好的选择:

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 整齐!我接受`TypedQuery <T>`,在这种情况下,`getResultList()`已经正确地输入为`List <T>`. (2认同)

小智 21

在Java 8中尝试这个:

Optional first = query.getResultList().stream().findFirst();
Run Code Online (Sandbox Code Playgroud)

  • 它可以更好:`em.createQuery("...").getResultStream().findFirst().orElse(null);`。 (4认同)
  • 您可以通过添加`.orElse(null)`来摆脱Optional (3认同)

hee*_*nee 16

Spring有一个实用方法:

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


Ser*_*ins 16

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

.getResultStream()
.findFirst()
.orElse(null);
Run Code Online (Sandbox Code Playgroud)


小智 10

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

query.getResultList().stream().findFirst().orElse(null);
Run Code Online (Sandbox Code Playgroud)

  • @EnricoGiurin,我已经编辑了代码段。干得好 没有尝试捕获,也没有list.size检查。最好的一种衬管解决方案。 (2认同)

Sor*_*ter 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); 
}
Run Code Online (Sandbox Code Playgroud)


Emm*_*ery 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);
}
Run Code Online (Sandbox Code Playgroud)


ace*_*es. 5

有一种我建议的替代方法:

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

这可以防止出现空指针异常,并确保仅返回1个结果。