web-dev-qa-db-fra.com

Requête JPA de données Spring avec propriétés de paramètre

Quel est le moyen le plus simple de déclarer une requête JPA de données Spring qui utilise les propriétés d'un paramètre d'entrée en tant que paramètres de requête?

Par exemple, supposons que j'ai une classe d'entité:

public class Person {
    @Id
    private long id;

    @Column
    private String forename;

    @Column
    private String surname;
}

et une autre classe:

public class Name {
    private String forename;
    private String surname;

    [constructor and getters]
}

... alors j'aimerais écrire un référentiel de données Spring comme suit:

public interface PersonRepository extends CrudRepository<Person, Long> {
    @Query("select p from Person p where p.forename = ?1.forename and p.surname = ?1.surname")
    findByName(Name name);
}

... mais Spring data/JPA n'aime pas que je spécifie des noms de propriétés sur le ?1 paramètre.

Quelle est la meilleure alternative?

46
Kkkev

Ce lien vous aidera: JPA M1 de Spring Data avec prise en charge des expressions SpEL. L'exemple similaire serait:

@Query("select u from User u where u.firstname = :#{#customer.firstname}")
List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);

https://spring.io/blog/2014/07/15/spel-support-in-spring-data-jpa-query-definitions

92
sunday

Définissez la méthode de requête avec les signatures comme suit.

@Query(select p from Person p where p.forename = :forename and p.surname = :surname)
User findByForenameAndSurname(@Param("surname") String lastname,
                             @Param("forename") String firstname);
}

Pour plus de détails, consultez la référence Spring Data JPA

20
CuriosMind...

Ce que tu veux n'est pas possible. Vous devez créer deux paramètres et les lier séparément:

select p from Person p where p.forename = :forename and p.surname = :surname
...
query.setParameter("forename", name.getForename());
query.setParameter("surname", name.getSurname());
10
JB Nizet

Vous pouvez essayer quelque chose comme ça:

public interface PersonRepository extends CrudRepository<Person, Long> {
       @Query("select p from Person AS p"
       + " ,Name AS n"  
       + " where p.forename = n.forename "
       + " and p.surname = n.surname"
       + " and n = :name")
       Set<Person>findByName(@Param("name") Name name);
    }
6
Casi

Vous pouvez également le résoudre avec une méthode d’interface par défaut:

 @Query(select p from Person p where p.forename = :forename and p.surname = :surname)
User findByForenameAndSurname(@Param("surname") String lastname,
                         @Param("forename") String firstname);

default User findByName(Name name) {
  return findByForenameAndSurname(name.getLastname(), name.getFirstname());
}

Bien sûr, vous auriez toujours la fonction de référentiel visible publiquement ...

4
mmey

si nous utilisons JpaRepository, les requêtes seront créées en interne.

échantillon

findByLastnameAndFirstname (nom de la chaîne, prénom de la chaîne)

findByLastnameOrFirstname (nom de la chaîne, prénom de la chaîne)

findByStartDateBetween (Date date1, Date2)

findById (id int)

Note

si supposons que nous avons besoin de requêtes complexes, nous devons écrire des requêtes manuelles comme

@Query("SELECT salesOrder FROM SalesOrder salesOrder WHERE salesOrder.clientId=:clientId AND salesOrder.driver_username=:driver_username AND salesOrder.date>=:fdate AND salesOrder.date<=:tdate ")
 @Transactional(readOnly=true)
 List<SalesOrder> findAllSalesByDriver(@Param("clientId")Integer clientId, @Param("driver_username")String driver_username, @Param("fdate") Date fDate, @Param("tdate") Date tdate);
1
Mohammad

Travaillez-vous avec un @Service aussi? Parce que si vous êtes, alors vous pouvez @Autowired votre PersonRepository au @Service puis dans le service, invoquez simplement la classe Name et utilisez le formulaire proposé par @CuriosMind ...

@Query(select p from Person p where p.forename = :forename and p.surname = :surname)
User findByForenameAndSurname(@Param("surname") String lastname,
                         @Param("forename") String firstname);
}

et lorsque vous appelez la méthode depuis le référentiel du service, vous pouvez ensuite transmettre ces paramètres.

1
Leo