web-dev-qa-db-fra.com

Requête Spring Data JPA et Exists

J'utilise Spring Data JPA (avec Hibernate en tant que fournisseur JPA) et je souhaite définir une méthode exists avec une requête HQL attachée:

public interface MyEntityRepository extends CrudRepository<MyEntity, String> {

  @Query("select count(e) from MyEntity e where ...")
  public boolean existsIfBlaBla(@Param("id") String id);

}

Lorsque je lance cette requête, je reçois un Java.lang.ClassCastException: Java.lang.Long cannot be cast to Java.lang.Boolean.

À quoi doit ressembler la requête HQL pour que cela fonctionne? Je sais que je pourrais simplement renvoyer une valeur Long et ensuite vérifier dans mon code Java si count > 0, mais cette solution de contournement ne devrait pas être nécessaire, non? 

36
Stefan Haberl

Je pense que vous pouvez simplement changer la requête pour retourner un booléen

@Query("select count(e)>0 from MyEntity e where ...")

PS: Si vous vérifiez qu’il existe en fonction de la valeur de la clé primaire CrudRepository, vous avez déjà la méthode exists(id).

46

Spring Data JPA 1.11 prend désormais en charge la projection exists dans la dérivation de la requête du référentiel.

Voir la documentation ici .

Dans votre cas, ce qui suit fonctionnera:

public interface MyEntityRepository extends CrudRepository<MyEntity, String> {  
    boolean existsByFoo(String foo);
}
108
Ankit Soni

Depuis Spring data 1.12, vous pouvez utiliser la fonctionnalité de la requête par exemple en étendant l'interface QueryByExampleExecutor (la JpaRepositoryalready l'étend).
Ensuite, vous pouvez utiliser cette requête (entre autres): 

<S extends T> boolean exists(Example<S> example);

Considérons une entité MyEntity qui, en tant que propriété name, souhaite savoir si une entité portant ce nom existe, en ignorant la casse, l'appel à cette méthode peut alors ressembler à ceci: 

//The ExampleMatcher is immutable and can be static I think
ExampleMatcher NAME_MATCHER = ExampleMatcher.matching()
            .withMatcher("name", GenericPropertyMatchers.ignoreCase());
Example<MyEntity> example = Example.<MyEntity>of(new MyEntity("example name"), NAME_MATCHER);
boolean exists = myEntityRepository.exists(example);
8
Stephane L

dans mon cas, cela n'a pas fonctionné comme suit 

@Query("select count(e)>0 from MyEntity e where ...")

Vous pouvez le renvoyer en valeur booléenne en suivant

@Query(value = "SELECT CASE  WHEN count(pl)> 0 THEN true ELSE false END FROM PostboxLabel pl ...")
7
Runomu

Outre la réponse acceptée, je suggère une autre alternative . Utilisez QueryDSL , créez un prédicat et utilisez la méthode exists() qui accepte un prédicat et retourne un booléen.

Un avantage avec QueryDSL est que vous pouvez utiliser le prédicat pour les clauses where compliquées.

1
Narasimha

Vous pouvez utiliser l'expression Case pour renvoyer une boolean dans votre requête select, comme ci-dessous.

@Query("SELECT CASE WHEN count(e) > 0 THEN true ELSE false END FROM MyEntity e where e.my_column = ?1")
0
Sahil Chhabra