setMaxResults для анотації Spring-Data-JPA?


127

Я намагаюся включити Spring-Data-JPA у свій проект. Одне, що мене бентежить, - як я досягти setMaxResults (n) за допомогою анотації?

наприклад, мій код:

public interface UserRepository extends CrudRepository<User , Long>
{
  @Query(value="From User u where u.otherObj = ?1 ")
  public User findByOhterObj(OtherObj otherObj);
}

Мені потрібно лише повернути one (and only one)Користувача з otherObj, але я не можу знайти спосіб анотувати maxResults. Може хтось підкаже мені?

(mysql скаржиться:

com.mysql.jdbc.JDBC4PreparedStatement@5add5415: select user0_.id as id100_, user0_.created as created100_ from User user0_ where user0_.id=2 limit ** NOT SPECIFIED **
WARN  util.JDBCExceptionReporter - SQL Error: 0, SQLState: 07001
ERROR util.JDBCExceptionReporter - No value specified for parameter 2

)

Я знайшов посилання: https://jira.springsource.org/browse/DATAJPA-147 , я спробував, але не вдалося. Мабуть, зараз це неможливо? Чому така важлива особливість не вбудована у Spring-Data?

Якщо я реалізую цю функцію вручну:

public class UserRepositoryImpl implements UserRepository

Мені доведеться реалізувати тонни заздалегідь визначених методів CrudRepository, це було б жахливо.

середовища: spring-3.1, spring-data-jpa-1.0.3.RELEASE.jar, spring-data-commons-core-1.1.0.RELEASE.jar

Відповіді:


176

Станом на Весняні дані JPA 1.7.0 (поїзд випуску Evans).

Ви можете використовувати нещодавно введені ключові слова Topта такі Firstключові слова, які дозволяють визначити такі методи запиту:

findTop10ByLastnameOrderByFirstnameAsc(String lastname);

Весняні дані автоматично обмежують результати числом, яке ви визначили (за замовчуванням до 1, якщо пропущено). Зауважте, що впорядкування результатів стає актуальним тут (або через OrderByпункт, як показано в прикладі, або шляхом передачі Sortпараметра методу). Детальніше про це читайте в публікації блогу, що висвітлює нові функції потягу Spring Data Evans або в документації .

Для попередніх версій

Щоб отримати лише фрагменти даних, Spring Data використовує абстрагування сторінки, що поставляється з Pageableінтерфейсом на запитуючій стороні, а також Pageабстракцією на стороні результатів. Так ви могли почати з

public interface UserRepository extends Repository<User, Long> {

  List<User> findByUsername(String username, Pageable pageable);
}

і використовувати його так:

Pageable topTen = new PageRequest(0, 10);
List<User> result = repository.findByUsername("Matthews", topTen);

Якщо вам потрібно знати контекст результату (яка сторінка це насправді? Це перша? Скільки їх усього?), Використовуйте Pageяк тип повернення:

public interface UserRepository extends Repository<User, Long> {

  Page<User> findByUsername(String username, Pageable pageable);
}

Потім клієнтський код може зробити щось подібне:

Pageable topTen = new PageRequest(0, 10);
Page<User> result = repository.findByUsername("Matthews", topTen);
Assert.assertThat(result.isFirstPage(), is(true));

Не те, що ми запустимо проекцію підрахунку фактичного запиту, який потрібно виконати, якщо ви використовуєте Pageяк тип повернення, оскільки нам потрібно з'ясувати, скільки елементів усього є для обчислення метаданих. Крім того, будьте впевнені, що ви фактично обладнали інформацію про PageRequestсортування, щоб отримати стабільні результати. В іншому випадку ви можете запустити запит двічі і отримати різні результати, навіть не змінюючи під собою дані.


14
Дякую, але я все ще сподіваюся на рішення на основі анотацій. Тому що "Сторінка / Pageable" в цьому випадку занадто надмірна. І клієнт повинен створити Pageable / Page, щоб отримати результат "один і єдиний" ... Користуватися дуже недоброзичливо. І, здається, ви відповідаєте за Spring-Data, сподіваюся, ви зможете детальніше розглянути цю проблему: stackoverflow.com/questions/9276461/… . Чи можете ви підтвердити, чи це помилка Spring-Data?
smallufo

1
+ це працює, дякую, але рішення, що базується на коментарях, було б краще в нових версіях
azerafati

1
тут запускається запит підрахунку, який абсолютно непотрібний, якщо ми хочемо обмежений запит.
azerafati

1
Це не якщо ви використовуєте Listяк зворотний тип методу.
Олівер Дротбом

3
Я думаю, Topа Firstключові слова не застосовуються до методів, які використовують @Queryанотацію? Тільки ті, хто використовує метод-ім'я на основі генерації запитів?
Руслан Стельмаченко

106

Якщо ви використовуєте Java 8 та Spring Data 1.7.0, ви можете використовувати методи за замовчуванням, якщо ви хочете поєднати @Queryпримітку із встановленням максимальних результатів:

public interface UserRepository extends PagingAndSortingRepository<User,Long> {
  @Query("from User u where ...")
  List<User> findAllUsersWhereFoo(@Param("foo") Foo foo, Pageable pageable);

  default List<User> findTop10UsersWhereFoo(Foo foo) {
    return findAllUsersWhereFoo(foo, new PageRequest(0,10));
  }

}

3
потенційно корисний для одного результатуStream<User> ... {...} default Optional<User> ... { ...findAny() }
ксенотерацид

28

Існує спосіб надати еквівалент "a setMaxResults (n) за допомогою анотації", наприклад у наступному:

public interface ISomething extends JpaRepository<XYZ, Long>
{
    @Query("FROM XYZ a WHERE a.eventDateTime < :before ORDER BY a.eventDateTime DESC")
    List<XYZ> findXYZRecords(@Param("before") Date before, Pageable pageable);
}

Це повинно зробити трюк, коли сторінка надсилається як параметр. Наприклад, щоб отримати перші 10 записів, вам потрібно встановити сторінкові значення для цього значення:

new PageRequest(0, 10)

Якщо ви використовуєте Pagable, тоді його повернення Сторінка <XYZ> не Список <XYZ>
Арундев

@Arundev неправильно - Listпрацює чудово (і уникає зайвого countзапиту, як уже згадувалося в попередньому коментарі )
Janaka Bandara

21

Використовуйте весняні дані Еванса (1.7.0 ЗВ'ЯЗКУ)

новий випуск Spring Data JPA з іншим списком модулів разом під назвою Evans має особливість використання ключових слів Top20і Firstобмеження результату запиту,

щоб ви могли зараз писати

List<User> findTop20ByLastname(String lastname, Sort sort);

або

List<User> findTop20ByLastnameOrderByIdDesc(String lastname);

або для єдиного результату

List<User> findFirstByLastnameOrderByIdDesc(String lastname);

5
Необов’язково <User> findFirstByLastnameOrderByIdDesc (прізвище рядка);
krmanish007

Отримавши результати top20, як я можу отримати наступні 20 результатів, коли я перейду на наступну сторінку веб-сайту за допомогою пагінації?
kittu

@kittu, це, звичайно, інше питання, але вам потрібно здати Pageableоб'єкт. перевірити весняну документацію
azerafati

чому вони зробили метод повернути проклятий список, якщо він вказаний ПЕРШИЙ ??
Василь Сурду

13

Найкращий вибір для мене - це власний запит:

@Query(value="SELECT * FROM users WHERE other_obj = ?1 LIMIT 1", nativeQuery = true)
User findByOhterObj(OtherObj otherObj);

Не впевнений, чи підтримується в Hibernate ліміт
Вітольд Качурба

2
Порушує всю концепцію! Краще використовувати EntityManager замість цього!
Spektakulatius

@ Code.IT Я поширюю концепцію KISS. Крім цього, nativeQuery доданий параметр анотації JPA не для ігнорування.
Григорій Кіслін

@GKislin, ніж вам потрібно перейменувати такий метод, як findLimitOneByOtherObj. Також ви забули додати OrderBy, що призводить до неправильного результату, якщо other_obj не унікальний. Інакше де заява в унікальній колонці має бути достатньою без обмежень
Spektakulatius

Ключове слово LIMIT - не сплячий, а postgres / mysql
Acewin,

5

Якщо ваш клас @Repositoryрозширюється, JpaRepositoryви можете використовувати приклад нижче.

int limited = 100;
Pageable pageable = new PageRequest(0,limited);
Page<Transaction> transactionsPage = transactionRepository.findAll(specification, pageable);
return transactionsPage.getContent();

getContent return a List<Transaction>.


що робити, якщо у мене є 2, де в запиті такі умови, як: це буде працювати? Я отримую це виняток org.springframework.data.mapping.PropertyReferenceException: Для типу типу Board не створено властивості.
Шайлеш

4

Це також можливо за допомогою @QueryHints. Нижче на прикладі використовується org.eclipse.persistence.config.QueryHints # JDBC_MAX_ROWS

@Query("SELECT u FROM User u WHERE .....")
@QueryHints(@QueryHint(name = JDBC_MAX_ROWS, value = "1"))
Voter findUser();

Я перевіряв цей код, але він не працює. Не виняток, але не належний результат сусідів. Також документація дуже тонка щодо QueryHints. Дивись нижче. docs.spring.io/spring-data/jpa/docs/1.7.1.RELEASE/reference/…
bogdan.rusu

IIRC, немає гарантій, що підказки на запити будуть дотримані. Це просто спосіб передавати "дружні рекомендації" до реалізації.
Priidu Neemre

Я пробую це @QueryHints({@QueryHint(name = org.hibernate.annotations.FETCH_SIZE, value = "1")})в режимі сплячки, але псевдонім :( не працює
Григорій Кіслін

2
org.hibernate.annotations.FETCH_SIZE розмір його вибору, його не обмежувати, не максимум результатів. Hiber cant
Журавський Віталій

4

new PageRequest(0,10)не працює в нових версіях Spring (я використовую 2.2.1.RELEASE). В основному, конструктор отримав додатковий параметр як Sortтип. Більше того, конструктор, protectedтож вам доведеться або використовувати один із його дочірніх класів або викликати його ofстатичний метод:

PageRequest.of(0, 10, Sort.sort(User.class).by(User::getFirstName).ascending()))

Ви також можете опустити використання Sortпараметра і неявно користуватися сортуванням за замовчуванням (сортувати за pk тощо):

PageRequest.of(0, 10)

Ваше оголошення функції має бути приблизно таким:

List<User> findByUsername(String username, Pageable pageable)

і функцією буде:

userRepository.findByUsername("Abbas", PageRequest.of(0,10, Sort.sort(User.class).by(User::getLastName).ascending());
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.