setMaxResults per l'annotazione Spring-Data-JPA?


128

Sto cercando di incorporare Spring-Data-JPA nel mio progetto. Una cosa che mi confonde è come ottengo setMaxResults (n) per annotazione?

ad esempio, il mio codice:

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

Devo solo restituire l' one (and only one)utente da otherObj, ma non riesco a trovare un modo per annotare maxResults. Qualcuno può darmi un suggerimento?

(mysql si lamenta:

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

)

Ho trovato un collegamento: https://jira.springsource.org/browse/DATAJPA-147 , ho provato ma non è riuscito. Non sembra possibile adesso? Perché una funzionalità così importante non è incorporata in Spring-Data?

Se implemento questa funzione manualmente:

public class UserRepositoryImpl implements UserRepository

Devo implementare tonnellate di metodi predefiniti in CrudRepository , questo sarebbe terribile.

ambienti: spring-3.1, spring-data-jpa-1.0.3.RELEASE.jar, spring-data-commons-core-1.1.0.RELEASE.jar

Risposte:


176

A partire da Spring Data JPA 1.7.0 (treno di rilascio di Evans).

È possibile utilizzare le nuove parole chiave Tope Firstche consentono di definire metodi di query come questo:

findTop10ByLastnameOrderByFirstnameAsc(String lastname);

Spring Data limiterà automaticamente i risultati al numero definito (valore predefinito 1 se omesso). Si noti che l'ordine dei risultati diventa rilevante qui (tramite una OrderByclausola come mostrato nell'esempio o inserendo un Sortparametro nel metodo). Maggiori informazioni al riguardo nel post del blog che copre le nuove funzionalità del rilascio di Spring Data Evans o nella documentazione .

Per le versioni precedenti

Per recuperare solo porzioni di dati, Spring Data utilizza l'astrazione di impaginazione che viene fornita con Pageableun'interfaccia sul lato richiedente e Pageun'astrazione sul lato dei risultati. Quindi potresti iniziare con

public interface UserRepository extends Repository<User, Long> {

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

e usalo in questo modo:

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

Se hai bisogno di conoscere il contesto del risultato (quale pagina è effettivamente? È la prima? Quanti ce ne sono in totale?), Usa Pagecome tipo di ritorno:

public interface UserRepository extends Repository<User, Long> {

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

Il codice client può quindi fare qualcosa del genere:

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

Non che attiveremo una proiezione di conteggio della query effettiva da eseguire nel caso in cui si utilizzi Pagecome tipo restituito poiché è necessario scoprire quanti elementi ci sono in totale per calcolare i metadati. Oltre a ciò, assicurati di dotare effettivamente le PageRequestinformazioni di ordinamento per ottenere risultati stabili. Altrimenti potresti attivare la query due volte e ottenere risultati diversi anche senza che i dati sottostanti siano cambiati.


14
Grazie, ma spero ancora in una soluzione "basata su annotazioni". Perché "Pagina / Paginabile" sono troppo eccessivi in ​​questo caso. E il cliente deve creare una pagina / paginabile per recuperare "uno e solo uno" risultato ... È molto poco amichevole da usare. E sembra che tu sia responsabile di Spring-Data, spero che tu possa esaminare ulteriormente questo problema: stackoverflow.com/questions/9276461/… . Puoi confermare se si tratta di un bug di Spring-Data?
smallufo

1
+ funziona, grazie ma una soluzione basata su annotazioni sarebbe migliore nelle versioni più recenti
azerafati

1
una query di conteggio viene attivata qui che è totalmente inutile se vogliamo una query limitata.
azerafati

1
Non lo è se usi Listcome tipo di ritorno del metodo.
Oliver Drotbohm

3
Penso Tope le Firstparole chiave non sono applicabili ai metodi che utilizzano l' @Queryannotazione? Solo quelli che utilizzano la generazione di query basata sul nome del metodo?
Ruslan Stelmachenko,

106

Se utilizzi Java 8 e Spring Data 1.7.0, puoi utilizzare metodi predefiniti se desideri combinare @Queryun'annotazione con l'impostazione dei risultati massimi:

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
potenzialmente utile per un singolo risultatoStream<User> ... {...} default Optional<User> ... { ...findAny() }
xenoterracide

28

C'è un modo per fornire l'equivalente di "a setMaxResults (n) per annotazione" come nel seguente:

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

Questo dovrebbe fare il trucco, quando un paginabile viene inviato come parametro. Ad esempio, per recuperare i primi 10 record devi impostare paginabile su questo valore:

new PageRequest(0, 10)

Se stai usando Pagable, la sua pagina di ritorno <XYZ> non List <XYZ>
Arundev

@Arundev sbagliato - Listfunziona perfettamente (ed evita una countquery non necessaria come già menzionato in un commento precedente )
Janaka Bandara

21

Usa Spring Data Evans (VERSIONE 1.7.0)

la nuova versione di Spring Data JPA con un altro elenco di moduli insieme chiamato Evans ha la caratteristica di utilizzare parole chiave Top20eFirst di limitare il risultato della query,

così ora puoi scrivere

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

o

List<User> findTop20ByLastnameOrderByIdDesc(String lastname);

o per un unico risultato

List<User> findFirstByLastnameOrderByIdDesc(String lastname);

5
Opzionale <User> findFirstByLastnameOrderByIdDesc (String lastname);
krmanish007

Dopo aver ottenuto i primi 20 risultati, come posso ottenere i prossimi 20 risultati quando vado alla pagina successiva del sito Web utilizzando l'impaginazione?
kittu

@kittu, questa ovviamente è un'altra domanda ma devi passare un Pageableoggetto. controlla la documentazione della primavera
azerafati

perché hanno fatto in modo che il metodo restituisse una dannata lista se è specificato PRIMA ??
Vasile Surdu

13

La scelta migliore per me è la query nativa:

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

Non sono sicuro che il limite sia supportato in Hibernate: forum.hibernate.org/viewtopic.php?f=9&t=939314
Witold Kaczurba

2
Rompe l'intero concetto! Meglio usare invece EntityManager!
Spektakulatius

@ Code.IT Propongo il concetto di KISS. A parte quel nativeQuery parametro di annotazione JPA aggiunto da non ignorare.
Grigory Kislin

@ GKislin che devi rinominare il tuo metodo come findLimitOneByOtherObj. Inoltre hai dimenticato di aggiungere un OrderBy che porta a un risultato sbagliato se l'altro_obj non è univoco. Altrimenti una dichiarazione where su una colonna unica dovrebbe essere sufficiente senza un limite
Spektakulatius

La parola chiave LIMIT non è ibernata ma postgres / mysql
Acewin

5

Se la tua classe si @Repositoryestende JpaRepository, puoi utilizzare l'esempio seguente.

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

getContent return a List<Transaction>.


cosa succede se ho 2 condizioni where nella query come, transactionRepository.findByFirstNameAndLastName (firstname, lastname)? funzionerà ? Ricevo questa eccezione org.springframework.data.mapping.PropertyReferenceException: Nessuna proprietà creata trovata per il tipo Board.
Shailesh,

4

È anche possibile usare @QueryHints. L'esempio seguente utilizza 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();

Ho testato questo codice ma non funziona. Nessuna eccezione, ma nessun risultato adeguato. Anche la documentazione è molto scarsa su QueryHints. Vedi sotto. docs.spring.io/spring-data/jpa/docs/1.7.1.RELEASE/reference/…
bogdan.rusu

IIRC, non ci sono garanzie che venga seguito un suggerimento per la query. È solo un modo per trasmettere "consigli amichevoli" all'implementazione.
Priidu Neemre

Lo provo con @QueryHints({@QueryHint(name = org.hibernate.annotations.FETCH_SIZE, value = "1")})in Hibernate, ma alias :( non funziona
Grigory Kislin

2
org.hibernate.annotations.FETCH_SIZE la sua dimensione di recupero, il suo non limite, non il massimo dei risultati. Hiber cant
Zhuravskiy Vitaliy

4

new PageRequest(0,10)non funziona nelle versioni Spring più recenti (sto usando 2.2.1.RELEASE). Fondamentalmente, il costruttore ha ottenuto un parametro aggiuntivo come Sorttipo. Inoltre, il costruttore è protectedcosì che devi usare una delle sue classi figlie o chiamare il suo ofmetodo statico:

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

Puoi anche omettere l'uso del Sortparametro e utilizzare implicitamente l'ordinamento predefinito (ordina per pacchetto, ecc.):

PageRequest.of(0, 10)

La tua dichiarazione di funzione dovrebbe essere qualcosa del genere:

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

e la funzione sarà:

userRepository.findByUsername("Abbas", PageRequest.of(0,10, Sort.sort(User.class).by(User::getLastName).ascending());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.