Запрос JPA Spring данных со свойствами параметров

Каков самый простой способ объявить запрос JPA данных Spring, который использует свойства входного параметра в качестве параметров запроса?

Например, предположим, что у меня есть класс сущности:

public class Person {
    @Id
    private long id;

    @Column
    private String forename;

    @Column
    private String surname;
}

и еще один класс:

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

    [constructor and getters]
}

... тогда я хотел бы написать репозиторий данных Spring следующим образом:

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);
}

... но Spring data / JPA не любит, когда я указываю имена свойств в параметре ?1.

Какая самая лучшая альтернатива?


person Kkkev    schedule 29.05.2012    source источник
comment
Должен ли он быть динамичным? Почему нельзя просто добавить таблицу Name после оператора from?   -  person Tulio F.    schedule 29.05.2012
comment
Name не обязательно является сущностью.   -  person Kkkev    schedule 29.05.2012


Ответы (8)


Эта ссылка поможет вам: Spring Data JPA M1 с поддержкой выражений SpEL. Аналогичный пример:

@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

person sunday    schedule 11.03.2015
comment
это spring-data-jpa 1.7.2 + и требует Spring 4 - person chrismarx; 14.05.2015
comment
Клиент, кажется, должен быть здесь сущностью, оценка POJO для меня не работает. - person Schaka; 15.03.2016
comment
Не пробовал с pojo, я могу подтвердить, что он работает по крайней мере с сущностями. Кто-то еще упомянул, что они столкнулись с проблемами, если они включают и объект, и дополнительные аргументы (см. Комментарии здесь) - spring.io/blog/2014/07/15/ - person chrismarx; 02.09.2016
comment
И я могу подтвердить, что у меня такая же проблема, даже с Spring boot 1.4 / spring 4 / spring data jpa 1.10 - - person chrismarx; 02.09.2016
comment
Привет, воскресенье, у меня это работает, я хотел бы кое-что спросить. если бы я использовал Param в репозитории, могу ли я использовать Dtos с аннотациями Param? - person J. Abel; 04.10.2019
comment
Потрясающие! Не нашел этого даже в документации. Спасибо, брув! - person de.la.ru; 19.12.2019

Определите метод запроса с подписями следующим образом.

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

Для получения дополнительной информации проверьте справочник по Spring Data JPA

person CuriosMind...    schedule 02.06.2014
comment
Это не отвечает на вопрос. Уместным моментом является то, что я хотел бы использовать свойства входного параметра в качестве параметров запроса, а не отдельные входные параметры. - person Kkkev; 02.06.2014
comment
Ой, я неправильно прочитал ваш запрос. Я считаю, что Spring Data JPA не поддерживает поддержку (возможно, даже JDBC не может; здесь я могу ошибаться). В качестве другой альтернативы (помимо подхода с настраиваемым репозиторием) вы можете написать метод оболочки службы, который принимает объект Person в качестве параметра и передает соответствующие параметры методу репозитория. Преимущество этого подхода заключается в том, что подпись, которую вы ожидали (передать объект Person), не повреждена, а также вы используете реализацию, предоставленную Spring Data JPA. - person CuriosMind...; 04.06.2014

То, что вы хотите, невозможно. Вам нужно создать два параметра и связать их отдельно:

select p from Person p where p.forename = :forename and p.surname = :surname
...
query.setParameter("forename", name.getForename());
query.setParameter("surname", name.getSurname());
person JB Nizet    schedule 29.05.2012
comment
Предположительно, это необходимо реализовать в пользовательском методе репозитория согласно static.springsource.org/spring-data/data-jpa/docs/current/? - person Kkkev; 30.05.2012
comment
Я знаю, как работает JPA, но не знаю, что для вас делают spring-data и что вы должны делать сами. Извините. - person JB Nizet; 30.05.2012

Вы можете попробовать что-то вроде этого:

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);
    }
person Casi    schedule 13.11.2015
comment
@Kkkev это правильно, вам нужно сделать имя сущностью для этого решения - person Casi; 04.12.2017

Вы также можете решить эту проблему с помощью метода интерфейса по умолчанию:

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

Конечно, у вас все еще будет фактическая функция репозитория, публично видимая ...

person mmey    schedule 22.12.2017

если мы используем JpaRepository, он будет создавать запросы внутри себя.

Образец

findByLastnameAndFirstname (String lastname, String firstname)

findByLastnameOrFirstname (String lastname, String firstname)

findByStartDateBetween (Дата, дата1, Дата2)

findById (int id)

Примечание

если предположим, что нам нужны сложные запросы, тогда нам нужно написать ручные запросы, например

@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);
person Mohammad Adil    schedule 25.09.2017

Вы тоже работаете с @Service? Потому что, если да, то вы можете @Autowired свой PersonRepository в @Service, а затем в службе просто вызвать класс Name и использовать форму, предложенную @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);
}

и при вызове метода из репозитория в службе вы можете передать эти параметры.

person Leo    schedule 10.05.2016

Простота Spring Data JPA заключается в том, что он пытается интерпретировать имя функции в репозитории без указания каких-либо дополнительных аннотаций @Query или @Param. Если вы указываете полное имя, попробуйте разбить его на имя и фамилию, а затем используйте что-то вроде этого -

HotelEntity findByName(String name);

Мой HotelEntity действительно содержит поле name, поэтому JPA пытается интерпретировать самостоятельно, чтобы вывести имя поля, которое я пытаюсь запросить, и создать последующий запрос внутри. Еще несколько свидетельств из документации JPA -  введите описание изображения здесь

Дополнительные сведения - здесь

person Anvita Shukla    schedule 16.05.2021