web-dev-qa-db-fra.com

Spring Data JPA findOne () change en facultatif comment l'utiliser?

J'apprends SpringBoot2.0 avec Java8.

Et j'ai suivi un exemple de tutoriel de création de blog.

Le code source du tutoriel est:

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

Mais ce code jette cette erreur:

categoryService.findOne (id)

Je songe à changer la méthode JPA findOne() en Optional< S >

Comment résoudre ça?

Plus d'informations:

C'est la méthode categoryService:

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

D'au moins, la version 2.0, Spring-Data-Jpa modifiée findOne().
Maintenant, findOne() n'a pas la même signature et le même comportement.
Auparavant, il était défini dans l'interface CrudRepository comme suit:

T findOne(ID primaryKey);

Maintenant, la seule méthode findOne() que vous trouverez dans CrudRepository est celle qui est définie dans l'interface QueryByExampleExecutor comme étant:

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

Ceci est finalement implémenté par SimpleJpaRepository, l'implémentation par défaut de l'interface CrudRepository.
Cette méthode est une requête par exemple et vous ne voulez pas que cela remplace.

En fait, la méthode ayant le même comportement est toujours présente dans la nouvelle API, mais le nom de la méthode a changé.
Il a été renommé de findOne() en findById() dans l'interface CrudRepository :

Optional<T> findById(ID id); 

Maintenant, il retourne un Optional. Ce qui n’est pas si mal pour éviter NullPointerException.

Ainsi, la méthode à invoquer est maintenant Optional<T> findById(ID id).

Comment l'utiliser?
Apprentissage Optional usage. Voici des informations importantes sur ses spécifications:

Un objet conteneur pouvant contenir ou non une valeur non nulle. Si une valeur est présente, isPresent () retournera true et get () renverra la valeur.

Des méthodes supplémentaires dépendant de la présence ou de l'absence d'une valeur contenue sont fournies, telles que orElse () (retourne une valeur par défaut si valeur n'est pas présente) et ifPresent () (exécute un bloc de code si la valeur est présente).


Quelques astuces sur l'utilisation de Optional avec Optional<T> findById(ID id).

Généralement, lorsque vous recherchez une entité par identifiant, vous souhaitez la renvoyer ou effectuer un traitement particulier si celui-ci n’est pas récupéré.

Voici trois exemples d'utilisation classiques.

1) Supposons que si l'entité est trouvée, vous voulez l'obtenir sinon vous voulez obtenir une valeur par défaut.

Vous pouvez écrire:

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

ou obtenez une valeur par défaut null si cela a du sens (même comportement qu'avant le changement d'API):

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

2) Supposons que si l'entité est trouvée, vous voulez la renvoyer, sinon vous voulez lever une exception.

Vous pouvez écrire:

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

3) Supposons que vous souhaitiez appliquer un traitement différent selon que l'entité est trouvée ou non (sans qu'il soit nécessaire de lever une exception).

Vous pouvez écrire:

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

La méthode a été renommée en findById(…) renvoyant un Optional de sorte que vous deviez gérer vous-même les absences:

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
6
Oliver Drotbohm

Optional api fournit des méthodes pour obtenir les valeurs. Vous pouvez vérifier la présence de la valeur isPresent() puis faire appel à get() ou vous pouvez appeler get() chaînée avec orElse() et fournir une valeur par défaut.

La dernière chose que vous pouvez essayer de faire est d'utiliser @Query() sur une méthode personnalisée.

2
Prashant

En effet, dans la dernière version de Spring Data, findOne renvoie une option. Si vous voulez récupérer l'objet à partir de Optional, vous pouvez simplement utiliser get () sur Optional. Tout d’abord, un référentiel doit renvoyer l’optionnel à un service, qui gère ensuite le cas dans lequel l’optif est vide. Ensuite, le service doit renvoyer l'objet au contrôleur.

0
Claudiu Guja

J'écris toujours une méthode par défaut "findByIdOrError" dans les dépôts/interfaces CrudRepository largement utilisés.

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

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