【问题标题】:Spring Data JPA findOne() change to Optional how to use this?Spring Data JPA findOne() 改为 Optional 怎么用?
【发布时间】:2018-08-25 06:50:38
【问题描述】:

我正在学习 SpringBoot2.0Java8

并且我遵循了一些博客制作教程示例。

教程源码为:

@GetMapping("/{id}/edit")
public String edit(@PathVariable Long id, Model model) {
  model.addAttribute("categoryDto", categoryService.findOne(id));
  return "category/edit";
}

但是这段代码抛出了这个错误:

categoryService.findOne(id)

我正在考虑将 JPA 的 findOne() 方法更改为 Optional< S >

如何解决?

更多信息:

这是 categoryService 方法:

public Category findOne(Long id) {
  return categoryRepository.findOne(id);
}

【问题讨论】:

  • 1.你能把链接放到你关注的博客上吗,或者你能显示完整的代码吗? categoryService 是如何声明的? 2. 你得到的异常是什么

标签: java spring spring-data-jpa


【解决方案1】:

至少从2.0版本,Spring-Data-Jpa修改findOne()
现在,findOne() 既没有相同的签名也没有相同的行为。
之前在CrudRepository接口中定义为:

T findOne(ID primaryKey);

现在,您将在 CrudRepository 中找到的单个 findOne() 方法在 QueryByExampleExecutor 接口中定义为:

<S extends T> Optional<S> findOne(Example<S> example);

最终由SimpleJpaRepository 实现,CrudRepository 接口的默认实现。
此方法是通过示例搜索进行查询,您不希望将其作为替代方法。

其实在新的API中还是有同样行为的方法,只是方法名变了。
CrudRepository接口中,它从findOne()重命名为findById()

Optional<T> findById(ID id); 

现在它返回一个Optional,这对于阻止NullPointerException 来说还不错。

所以,现在实际调用的方法是Optional&lt;T&gt; findById(ID id)

如何使用它?
学习Optional 用法。 以下是有关其规范的重要信息:

一个容器对象,它可能包含也可能不包含非空值。如果一个 值存在,isPresent() 将返回 true,get() 将返回 价值。

其他方法取决于是否存在 提供了包含的值,例如 orElse() (返回默认值 如果值不存在)和 ifPresent()(如果 值存在)。


关于如何使用OptionalOptional&lt;T&gt; findById(ID id) 的一些提示。

通常,当您通过 id 查找实体时,您希望将其返回或在未检索到时进行特定处理。

以下是三个经典用法示例。

  1. 假设如果找到实体,您想要获取它,否则您想要获取默认值。

你可以写:

Foo foo = repository.findById(id)
                    .orElse(new Foo());

或在有意义的情况下获取 null 默认值(与 API 更改之前的行为相同):

Foo foo = repository.findById(id)
                    .orElse(null);
  1. 假设如果实体被发现你想返回它,否则你想抛出一个异常。

你可以写:

return repository.findById(id)
        .orElseThrow(() -> new EntityNotFoundException(id));
  1. 假设您想根据是否找到实体应用不同的处理(不一定抛出异常)。

你可以写:

Optional<Foo> fooOptional = fooRepository.findById(id);
if (fooOptional.isPresent()) {
    Foo foo = fooOptional.get();
    // processing with foo ...
} else {
    // alternative processing....
}

【讨论】:

  • thx david :) NotFoundEntity is extends RuntimeException { super("could not found " + id );像这样?
  • 第一部分是错误的:该方法没有被移动到QueryByExampleExecutor,它只是被重命名为findById(…),返回一个Optional。此外,始终在Optional 上使用….map(…),切勿致电get()
  • 谢谢 davidxxx。你救了我
  • 也许 EntityNotFoundException 而不是 NotFoundEntity 更好。
  • @zhouji 同意并更新。此外,它在javax.persistence API 中定义为RuntimeException。所以真的很有意义。
【解决方案2】:

该方法已重命名为 findById(…) 返回一个 Optional,因此您必须自己处理缺勤:

Optional<Foo> result = repository.findById(…);

result.ifPresent(it -> …); // do something with the value if present
result.map(it -> …); // map the value if present
Foo foo = result.orElse(null); // if you want to continue just like before

【讨论】:

【解决方案3】:

确实,在最新版本的 Spring Data 中,findOne 返回了一个可选项。如果要从 Optional 中检索对象,只需在 Optional 上使用 get()。首先,存储库应该将可选项返回给服务,然后由服务处理可选项为空的情况。之后,服务应该将对象返回给控制器。

【讨论】:

  • 建议在Optional 上致电….get() 是个坏建议。 Optional 有专门的方法来处理值。
  • 确实,为了处理值,还有更好的方法,比如.orElse()或者.orElseThrow()。但是对于简单地检索项目而不检查存储库调用是否返回所需的对象,.get() 应该只是这样做
【解决方案4】:

我总是在广泛使用的 CrudRepository 存储库/接口中编写默认方法 “findByIdOrError”

@Repository 
public interface RequestRepository extends CrudRepository<Request, Integer> {

    default Request findByIdOrError(Integer id) {
        return findById(id).orElseThrow(EntityNotFoundException::new);
    } 
}

【讨论】:

  • 但这会返回一个 Request 对象。我应该如何将其转换为我正在寻找的实体(如果存在)?
【解决方案5】:

Optional api 提供了获取值的方法。您可以检查isPresent() 是否存在该值,然后调用get(),或者您可以调用与orElse() 链接的get() 并提供默认值。

您可以尝试做的最后一件事是在自定义方法上使用@Query()

【讨论】:

  • 建议在Optional 上致电….get() 是个坏建议。 Optional 有专门的方法来处理这个值。
【解决方案6】:

考虑一个 User 实体和 UserRepository。在如下服务包代码中。

Optional<User> resultUser = UserRepository.findById(userId);  //return Optional

User createdUser = resultUser.get();  //return User

现在您可以使用 getter 访问所有用户实体属性。

createdUser.getId(); 
createdUser.getName();

这样。

【讨论】:

    【解决方案7】:

    自 Spring Data Commons 2.0 版起,CrudRepository interfacefindOne 方法已被 findById 取代。 你将findOne(id)替换为:

    findById(id).orElse(null)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-25
      • 2018-02-26
      • 1970-01-01
      • 1970-01-01
      • 2018-04-18
      相关资源
      最近更新 更多