wake-up-neo.com

Frühlingsdaten und native Abfrage mit Seitenumbruch

In einem Webprojekt, das die neuesten Spring-Daten (1.10.2) mit einer MySQL 5.6-Datenbank verwendet, versuche ich, eine native Abfrage mit Paginierung zu verwenden, aber ich habe beim Start einen org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException

UPDATE: 20180306 Dieses Problem ist jetzt in Spring 2.0.4 behoben. Für alle, die sich noch für ältere Versionen interessieren, sollten Sie die entsprechenden Antworten und Kommentare zu Problemlösungen durchsuchen.

Gemäß Example 50 at Using @Query from spring-data documentation ist es möglich, die Query selbst und eine countQuery wie folgt anzugeben:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

Aus Neugierde kann ich in NativeJpaQuery class feststellen, dass sie den folgenden Code enthält, um zu überprüfen, ob es sich um eine gültige jpa-Abfrage handelt:

public NativeJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, EvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
   super(method, em, queryString, evaluationContextProvider, parser);
   JpaParameters parameters = method.getParameters();
   boolean hasPagingOrSortingParameter = parameters.hasPageableParameter() || parameters.hasSortParameter();
   boolean containsPageableOrSortInQueryExpression = queryString.contains("#pageable") || queryString.contains("#sort");
   if(hasPagingOrSortingParameter && !containsPageableOrSortInQueryExpression) {
       throw new InvalidJpaQueryMethodException("Cannot use native queries with dynamic sorting and/or pagination in method " + method);
   }
}

Meine Abfrage enthält einen Pageable-Parameter, also hasPagingOrSortingParameter ist true, sucht aber auch nach einer #pageable- oder #sort-Sequenz in der queryString, die ich nicht zur Verfügung stelle.

Ich habe versucht, am Ende meiner Abfrage #pageable (es ist ein Kommentar) hinzuzufügen. Dadurch wird die Validierung bestanden. Bei der Ausführung schlägt die Ausführung jedoch fehl, da die Abfrage einen zusätzlichen Parameter erwartet: 3 statt 2.

Wenn ich containsPageableOrSortInQueryExpression manuell von false in true ändere, funktioniert die Abfrage gut. Ich kann also nicht wissen, warum diese Zeichenfolge in meiner queryString vorhanden ist, und ich weiß nicht, wie ich sie liefern soll.

Jede Hilfe wäre sehr dankbar.

Update 30.01.2014.__: Es scheint, dass die Entwickler von spring-data project an einem Fix für dieses Problem mit einem PR von Jens Schauder arbeiten .

38
Lasneyx

Ich entschuldige mich im Voraus, das fasst die ursprüngliche Frage und den Kommentar von Janar ziemlich gut zusammen.

Ich stieß auf das gleiche Problem: Ich fand das Beispiel 50 von Spring Data als die Lösung für mein Bedürfnis, eine native Abfrage mit Paginierung zu haben, aber Spring beschwerte sich beim Start, dass ich die Paginierung nicht mit nativen Anfragen verwenden konnte.

Ich wollte nur mitteilen, dass es mir gelungen ist, die native Abfrage, die ich brauchte, mit Paginierung mit folgendem Code erfolgreich auszuführen:

    @Query(value="SELECT a.* "
            + "FROM author a left outer join mappable_natural_person p on a.id = p.provenance_id "
            + "WHERE p.update_time is null OR (p.provenance_name='biblio_db' and a.update_time>p.update_time)"
            + "ORDER BY a.id \n#pageable\n", 
        /*countQuery="SELECT count(a.*) "
            + "FROM author a left outer join mappable_natural_person p on a.id = p.provenance_id "
            + "WHERE p.update_time is null OR (p.provenance_name='biblio_db' and a.update_time>p.update_time) \n#pageable\n",*/
        nativeQuery=true)
public List<Author> findAuthorsUpdatedAndNew(Pageable pageable);

Die countQuery (die im Codeblock auskommentiert ist) wird benötigt, um Page<Author> als Rückgabetyp der Abfrage zu verwenden. Die Zeilenumbrüche um den Kommentar "#pageable" sind erforderlich, um den Laufzeitfehler der Anzahl der erwarteten Parameter zu vermeiden (Problemumgehung der Problemumgehung). Ich hoffe, dass dieser Fehler bald behoben wird ...

31
Emanuele Fusco

Dieser Code funktioniert mit PostgreSQL und MySQL:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 ORDER BY ?#{#pageable}",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

ORDER BY ?#{#pageable} ist für Pageable.countQuery ist für Page<>.

15
Dmitry Stolbov

Nur für den Datensatz, der H2 als Testdatenbank und MySQL zur Laufzeit verwendet, funktioniert dieser Ansatz (Beispiel ist neuestes Objekt in Gruppe ):

@Query(value = "SELECT t.* FROM t LEFT JOIN t AS t_newer " +
        "ON t.object_id = t_newer.object_id AND t.id < t_newer.id AND o_newer.user_id IN (:user_ids) " +
        "WHERE t_newer.id IS NULL AND t.user_id IN (:user_ids) " +
        "ORDER BY t.id DESC \n-- #pageable\n",
        countQuery = "SELECT COUNT(1) FROM t WHERE t.user_id IN (:user_ids) GROUP BY t.object_id, t.user_id",
        nativeQuery = true)
Page<T> findByUserIdInGroupByObjectId(@Param("user_ids") Set<Integer> userIds, Pageable pageable);

Spring Data JPA 1.10.5, H2 1.4.194, MySQL Community Server 5.7.11-Protokoll (Innodb-Version 5.7.11).

10
maricn

Ich habe genau das gleiche Symptom wie @ Lasneyx. Mein Workaround für Postgres native Abfrage

@Query(value = "select * from users where user_type in (:userTypes) and user_context='abc'--#pageable\n", nativeQuery = true)
List<User> getUsersByTypes(@Param("userTypes") List<String> userTypes, Pageable pageable);
6
689

Versuche dies:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 ORDER BY /*#pageable*/",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

("/* */" für Oracle notation)

5
XmasPiano

Ich verwende eine Oracle-Datenbank und erhielt nicht das Ergebnis, sondern einen Fehler mit dem generierten Komma, über das der D-Man oben spricht.

Dann war meine Lösung:

Pageable pageable = new PageRequest(current, rowCount);

Wie Sie ohne Auftrag sehen können, wenn Sie Pagable erstellen.

Und die Methode in der DAO:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 /*#pageable*/ ORDER BY LASTNAME",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
 }
3
Pulszar

Die folgenden Ansätze funktionieren gut mit MySQL, um die native Abfrage zu paginieren. Sie arbeiten jedoch nicht mit H2. Es wird der SQL-Syntaxfehler beanstandet.

  • ORDER BY? # {# Pageable}
  • ORDER BY a.id\n # pageable\n
2
wmao

Die Verwendung von "ORDER BY id DESC\n-- #pageable\n" Anstelle von "ORDER BY id\n # pageable\n" funktionierte für mich mit MS SQL SERVER

1
Muhamed Saudi

Durch Ersetzen von / #pageable / durch? # {# Pageable} können Sie die Paginierung ausführen. Durch das Hinzufügen von PageableDefault können Sie die Größe der Seitenelemente festlegen. 

0
Mohit Thakkar

Es funktioniert wie folgt:

public interface UserRepository extends JpaRepository<User, Long> {
    @Query(value = "select * from (select (@rowid\\:[email protected]+1) as RN, u.* from USERS u, (SELECT @rowid\\:=0) as init where  LASTNAME = ?1) as total"+
        "where RN between ?#{#pageable.offset-1} and ?#{#pageable.offset + #pageable.pageSize}",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
    Page<User> findByLastname(String lastname, Pageable pageable);
}
0
Fonda Wu