Spring Данные JPA findOne() изменить на Необязательно как это использовать?

Я изучаю SpringBoot2.0 с помощью Java8.

И я последовал примеру учебного примера для блога.

Исходный код учебника:

@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

По крайней мере, версия 2.0 Spring-Data-Jpa модифицировала findOne().
Теперь findOne() не имеет одинаковую подпись и одинаковое поведение.
Ранее это было определено в интерфейсе CrudRepository как:

T findOne(ID primaryKey);

Теперь единственный findOne() который вы найдете в CrudRepository - это метод, который определен в интерфейсе QueryByExampleExecutor как:

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

Наконец, это реализуется SimpleJpaRepository, реализацией по CrudRepository интерфейса CrudRepository.
Этот метод является запросом по примеру поиска, и вы не хотите использовать его в качестве замены.

Фактически, метод с таким же поведением все еще присутствует в новом API, но имя метода изменилось.
Он был переименован из findOne() в findById() в интерфейсе CrudRepository:

Optional<T> findById(ID id); 

Теперь он возвращает Optional. Что не так плохо, чтобы предотвратить исключение NullPointerException.

Итак, фактический метод для вызова теперь является Optional<T> findById(ID id).

Как это использовать?
Обучение по Optional. Вот важная информация о его спецификации:

Контейнерный объект, который может содержать или не содержать ненулевое значение. Если значение присутствует, isPresent() вернет true, а get() вернет значение.

Предоставляются дополнительные методы, которые зависят от наличия или отсутствия содержащегося в нем значения, например orElse() (возвращают значение по умолчанию, если значение отсутствует) и ifPresent() (выполняют блок кода, если значение присутствует).


Некоторые советы о том, как использовать Optional с Optional<T> findById(ID id).

Обычно, когда вы ищете сущность по идентификатору, вы хотите вернуть ее или выполнить определенную обработку, если она не найдена.

Вот три классических примера использования.

1) Предположим, что если сущность найдена, вы хотите получить ее, иначе вы хотите получить значение по умолчанию.

Вы могли бы написать:

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

или получите null значение по умолчанию, если оно имеет смысл (то же поведение, что и до изменения API):

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

2) Предположим, что если сущность найдена, вы хотите вернуть ее, иначе вы хотите вызвать исключение.

Вы могли бы написать:

return repository.findById(id)
        .orElseThrow(() -> new EntityNotFoundException(id));

3) Предположим, что вы хотите применить другую обработку в зависимости от того, найдена сущность или нет (без необходимости исключения).

Вы могли бы написать:

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

Ответ 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

Optional api предоставляет методы для получения значений. Вы можете проверить isPresent() на наличие значения, а затем сделать вызов get(), или вы можете сделать вызов get(), связанный с orElse(), и предоставить значение по умолчанию.

Последнее, что вы можете попробовать сделать, это использовать @Query() по пользовательскому методу.

Ответ 4

В самом деле, в последней версии Spring Data, findOne возвращает необязательный. Если вы хотите получить объект из опции "Дополнительно", вы можете просто использовать get() в опции "Дополнительно". Прежде всего, хотя репозиторий должен вернуть необязательный сервис, который затем обрабатывает случай, в котором необязательный пуст. после этого служба должна вернуть объект контроллеру.

Ответ 5

Я всегда пишу метод по умолчанию "findByIdOrError" в широко используемых репозиториях/интерфейсах CrudRepository.

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

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