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?
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
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
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());
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);
}
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 ...
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);
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.