setMaxResults для аннотации Spring-Data-JPA?
Я пытаюсь включить 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
10 ответов
По состоянию на Spring Data JPA 1.7.0 (выпуск Эванса).
... вы можете использовать недавно введенный Top
а также First
ключевые слова, которые позволяют вам определять методы запроса, подобные этим:
findTop10ByLastnameOrderByFirstnameAsc(String lastname);
Spring Data автоматически ограничит результаты указанным вами числом (по умолчанию 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
с сортировкой информации для получения стабильных результатов. В противном случае вы можете запустить запрос дважды и получить разные результаты, даже если данные не изменились.
Если вы используете 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));
}
}
Существует способ, которым вы можете предоставить эквивалент "a setMaxResults(n) by annotation", как показано ниже:
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 записей, вам нужно установить pageable в это значение:
new PageRequest(0, 10)
Используйте Spring Data Evans (1.7.0 RELEASE)
новая версия Spring Data JPA с другим списком модулей под названием Evans имеет функцию использования ключевых слов Top20
а также First
ограничить результат запроса,
так что теперь вы можете написать
List<User> findTop20ByLastname(String lastname, Sort sort);
или же
List<User> findTop20ByLastnameOrderByIdDesc(String lastname);
или для одного результата
List<User> findFirstByLastnameOrderByIdDesc(String lastname);
Лучший выбор для меня - это нативный запрос:
@Query(value="SELECT * FROM users WHERE other_obj = ?1 LIMIT 1", nativeQuery = true)
User findByOhterObj(OtherObj otherObj);
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());
Это также возможно с использованием @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();
Если ваш класс @Repository
продолжается JpaRepository
Вы можете использовать пример ниже.
int limited = 100;
Pageable pageable = new PageRequest(0,limited);
Page<Transaction> transactionsPage = transactionRepository.findAll(specification, pageable);
return transactionsPage.getContent();
getContent возвращает List<Transaction>
,
Я не могу поверить спустя 12 лет. Sping-Data-JPA до сих пор не имеет реального решения. В итоге я написал собственную реализацию репозитория.
public class CustomJpaRepository <Entity, Id> extends JpaRepositoryImplementation<Entity, Id> {
Optional<Entity> findFirst(String query, Map<String, Object> parameters, String entityGraph);
}
public class CustomExtendedJpaRepository<E, I> extends SimpleJpaRepository<E, I> implements ExtendedJpaRepository<E, I>{
private final EntityManager entityManager;
private final Class<E> domainClass;
public CustomExtendedJpaRepository(JpaEntityInformation<E, I> entityInformation, EntityManager em) {
super(entityInformation, em);
this.entityManager = em;
this.domainClass = entityInformation.getJavaType();
}
public CustomExtendedJpaRepository(Class<E> domainClass, EntityManager em) {
super(domainClass, em);
this.entityManager = em;
this.domainClass = domainClass;
}
@Override
public Optional<E> findFirst(String query, Map<String, Object> parameters, String entityGraph) {
var tq = entityManager.createQuery(query, domainClass);
for (var p : parameters.entrySet()) {
tq.setParameter(p.getKey(), p.getValue());
}
if (entityGraph != null) {
tq.setHint(AvailableHints.HINT_SPEC_FETCH_GRAPH, entityManager.getEntityGraph(entityGraph));
}
tq.setMaxResults(1);
return Optional.ofNullable(tq.getSingleResult());
}
}
Чтобы включить пользовательскую реализацию
@EnableJpaRepositories(
basePackages = "your.company.persistence",
repositoryBaseClass = CustomExtendedJpaRepository.class
)
Использовать
Pageable pageable = PageRequest.of(0,1);
Page<Transaction> transactionsPage = transactionRepository.findAll(specification, pageable);
return transactionsPage.getContent();